Bootstrap

详细示例,讲解事件循环(Event Loop)机制,看这一篇就够了。

1.浏览器中的线程有以下几种:

  • js执行线程
  • GUI渲染线程
  • 事件监听线程
  • 计时器计时线程
  • 网络通信线程

2.如何理解js单线程?

之所以说js单线程,是因为它的执行引擎只有一个线程,并且不会在执行期间开启新的线程。而并非是指浏览器单线程。

3.js执行栈

js线程执行任务时,会创建js执行栈。同步任务直接推入执行栈中执行,异步任务推入事件队列中,注册回调函数。当执行栈空闲时,js会去事件队列中读取事件当初注册的回调函数,到执行栈中,并执行函数。

4.事件队列中异步任务划分

异步任务分为宏任务和微任务。

  • 宏任务:script, settimeout,ajax请求,dom事件
  • 微任务:Promise.then、MutationObserver、process.nextTick()

当宏任务执行完,执行栈空闲时,js首先会将队列中的所有微任务执行完,再去执行宏队列中的宏任务。如此反复,就是事件循环了。

一轮循环是这样的:是一次宏任务加上当前所有微任务执行。当js执行时,先执行宏任务(其实,就是当前宏任务中所有的同步任务),遇到微任务,则推入微队列,并注册回调函数。当该次宏任务执行完后,会读取微任务注册的回调函数到执行栈中执行。执行完后。继续下一轮循环。

看下面这个示例:

setTimeout(function () {
  console.log('three');
}, 0);

Promise.resolve().then(function () {
  console.log('two');
});

console.log('one');
结果:
// one
// two
// three

分析:

  • 首先整段代码可以看做是宏任务

  • 当js执行时,遇到setTimeout,它是宏任务,则放入宏队列,等待本轮执行完后,在一轮循环中执行。然后遇到了promise的then,则被推入微队列。

  • 接着,打印one。好了,到此,本轮宏任务已经执行完毕,但是,本次循环并未结束。

  • 然后,js去微队列中读取then注册的回调函数执行,打印two

  • 注意了!!!到此,本轮所有任务执行完毕,本次事件循环结束了。

  • 接着,开启下一轮循环,执行settimeout,打印three。所以,输出结果为:

one
two
three

再看个示例

console.log('1');
setTimeout(function () {
    console.log('2');
    process.nextTick(function () {
        console.log('3');
    })
    new Promise(function (resolve) {
        console.log('4');
        resolve();
    }).then(function () {
        console.log('5')
    })
})
process.nextTick(function () {
    console.log('6');
})
new Promise(function (resolve) {
    console.log('7');
    resolve();
}).then(function () {
    console.log('8')
})

setTimeout(function () {
    console.log('9');
    process.nextTick(function () {
        console.log('10');
    })
    new Promise(function (resolve) {
        console.log('11');
        resolve();
    }).then(function () {
        console.log('12')
    })
})

输出如下:
在这里插入图片描述
大家可以根据上一个例子的分析模式,分析看看。

最后

当promise的then()和process的nextTick()处在同一个宏任务中时,nextTick()先于then()执行。
示例:

new Promise(function (resolve) {
    console.log(3);
    resolve();
    console.log(4);
}).then(function () {
    console.log(5);
});
process.nextTick(function () {
    console.log(8);
});
process.nextTick(function () {
    console.log(7);
});

输出:
在这里插入图片描述

;