javascript的异步机制

前端语法/样式/布局 2016-11-06

起步

js编程总是伴随着异步操作,使得我们习惯的“线性”执行变得不一样,我们常用的异步操作:定时器setTimeout,事件绑定onclick,异步请求XMLHttpRequest,还有一些不常用的PromisesWebWorkor

js是单线程的

异步的存在让其他代码处于无阻塞状态,单线程的js是如何做到这点呢?先声明,js是单线程的这句话没错,哪怕通过延时去触发:

function foo() {
    console.log('first' );
}

setTimeout(function(){
    console.log( 'second' );
}, 5);

for (var i = 0; i < 10000; i++) {
    foo();
}

它的输出,执行结果会首先全部输出first,然后全部输出second;尽管中间的执行会超过5ms:

20161106001609.png

setTimeout(func, 5)为什么有时候没用?因为js是单线程处理的,它只有处理完当前的事情才会接着去处理其他事情,延时事件到要运行函数了,但js此时还忙于处理for循环。

浏览器是多线程的

js运行在浏览器中,是单线程的,每个window一个js线程,但浏览器不是单线程的。浏览器很多行为都是异步的,这些异步很多事通过 事件驱动 触发的。浏览器有一个内部的消息循环,Event Loop(事件循环),会轮询大的事件队列并处理事件。当异步事件发生时,如:mouse click XMLHttpRequest setTimeout事件发生,将他们放入执行队列,等待当前代码执行完成。哪怕多个事件重叠发生,比如浏览器当前正在忙于处理onclick事件,这时另外一个事件发生了onsize,这个异步事件就被放入事件队列等待处理,只有前面的处理完毕了,空闲了才会执行这个事件。

setTimeout也是一样,当调用的时候,js引擎会启动定时器timer,大约xxms以后执行xxx,当定时器时间到,就把该事件放到主事件队列等待处理,至于真正处理就得等线程空闲下来了。setTimeout并不算是真异步,这只是假象。

Ajax异步请求是否真的异步? Ajax请求确实是异步的 ,这请求是由浏览器新开一个线程请求,事件回调的时候是放入Event loop单线程事件队列等候处理。就是说,请求是浏览器发起的,真的是异步,但是回调函数会放到事件队列,什么时候处理要看js有没有空了。

$.ajax({
    url:'./index.php',
    success: function (data) {
        console.log('ajax callback');
    }
});

for (var i = 0; i < 2000; i++) {
    console.log('for');
}

20161106090134.png

总结

js是单线程的,异步事件排队等待执行。当线程忙于处理其它事情时,就不能对用户的鼠标点击和键盘操作做出响应。


本文由 hongweipeng 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处。

如果对您有用,您的支持将鼓励我继续创作!