深入了解事件循环机制,Promise,setTimeout,process.nextTick

首先要了解宏任务和微任务:

宏任务大概包括:script(整体代码), setTimeout, setInterval, setImmediate, I/O, UI rendering。

微任务大概包括:process.nextTick, Promise, Object.observe(已废弃), MutationObserver(html5新特性)

当宏任务中的微任务执行结束后,就结束一轮循环。

测试:

有这样一串代码:

// demo02
console.log("golb1");

setTimeout(function () {
  console.log("timeout1");
  process.nextTick(function () {
    console.log("timeout1_nextTick");
  });
  new Promise(function (resolve) {
    console.log("timeout1_promise");
    resolve();
  }).then(function () {
    console.log("timeout1_then");
  });
});

setImmediate(function () {
  console.log("immediate1");
  process.nextTick(function () {
    console.log("immediate1_nextTick");
  });
  new Promise(function (resolve) {
    console.log("immediate1_promise");
    resolve();
  }).then(function () {
    console.log("immediate1_then");
  });
});

process.nextTick(function () {
  console.log("glob1_nextTick");
});
new Promise(function (resolve) {
  console.log("glob1_promise");
  resolve();
}).then(function () {
  console.log("glob1_then");
});

setTimeout(function () {
  console.log("timeout2");
  process.nextTick(function () {
    console.log("timeout2_nextTick");
  });
  new Promise(function (resolve) {
    console.log("timeout2_promise");
    resolve();
  }).then(function () {
    console.log("timeout2_then");
  });
});

process.nextTick(function () {
  console.log("glob2_nextTick");
});
new Promise(function (resolve) {
  console.log("glob2_promise");
  resolve();
}).then(function () {
  console.log("glob2_then");
});

setImmediate(function () {
  console.log("immediate2");
  process.nextTick(function () {
    console.log("immediate2_nextTick");
  });
  new Promise(function (resolve) {
    console.log("immediate2_promise");
    resolve();
  }).then(function () {
    console.log("immediate2_then");
  });
});

我们逐一分析:

第一步:宏任务script首先执行。全局入栈。glob1输出。

图片

第二步,执行过程遇到setTimeout。setTimeout作为任务分发器,将任务分发到对应的宏任务队列中。

setTimeout(function() {    console.log('timeout1');    process.nextTick(function() {        console.log('timeout1_nextTick');    })    new Promise(function(resolve) {        console.log('timeout1_promise');        resolve();    }).then(function() {        console.log('timeout1_then')    })})

图片

第三步:执行过程遇到setImmediate。setImmediate也是一个宏任务分发器,将任务分发到对应的任务队列中。setImmediate的任务队列会在setTimeout队列的后面执行。

setImmediate(function() {    console.log('immediate1');    process.nextTick(function() {        console.log('immediate1_nextTick');    })    new Promise(function(resolve) {        console.log('immediate1_promise');        resolve();    }).then(function() {        console.log('immediate1_then')    })})

图片

第四步:执行遇到nextTick,process.nextTick是一个微任务分发器,它会将任务分发到对应的微任务队列中去。​​​​​​​

process.nextTick(function() {    console.log('glob1_nextTick');})

图片

第五步:执行遇到Promise。Promise的then方法会将任务分发到对应的微任务队列中,但是它构造函数中的方法会直接执行。因此,glob1_promise会第二个输出。​​​​​​​

new Promise(function(resolve) {    console.log('glob1_promise');    resolve();}).then(function() {    console.log('glob1_then')})

图片

图片

第六步:执行遇到第二个setTimeout。​​​​​​​

setTimeout(function() {    console.log('timeout2');    process.nextTick(function() {        console.log('timeout2_nextTick');    })    new Promise(function(resolve) {        console.log('timeout2_promise');        resolve();    }).then(function() {        console.log('timeout2_then')    })})

图片

第七步:先后遇到nextTick与Promise​​​​​​​

process.nextTick(function() {    console.log('glob2_nextTick');})new Promise(function(resolve) {    console.log('glob2_promise');    resolve();}).then(function() {    console.log('glob2_then')})

图片

第八步:再次遇到setImmediate。​​​​​​​

setImmediate(function() {    console.log('immediate2');    process.nextTick(function() {        console.log('immediate2_nextTick');    })    new Promise(function(resolve) {        console.log('immediate2_promise');        resolve();    }).then(function() {        console.log('immediate2_then')    })})

图片

这个时候,script中的代码就执行完毕了,执行过程中,遇到不同的任务分发器,就将任务分发到各自对应的队列中去。接下来,将会执行所有的微任务队列中的任务。

其中,nextTick队列会比Promie先执行。nextTick中的可执行任务执行完毕之后,才会开始执行Promise队列中的任务。

当所有可执行的微任务执行完毕之后,这一轮循环就表示结束了。下一轮循环继续从宏任务队列开始执行。

这个时候,script已经执行完毕,所以就从setTimeout队列开始执行。

图片

setTimeout任务的执行,也依然是借助函数调用栈来完成,并且遇到任务分发器的时候也会将任务分发到对应的队列中去。

只有当setTimeout中所有的任务执行完毕之后,才会再次开始执行微任务队列。并且清空所有的可执行微任务。

setTiemout队列产生的微任务执行完毕之后,循环则回过头来开始执行setImmediate队列。仍然是先将setImmediate队列中的任务执行完毕,再执行所产生的微任务。

当setImmediate队列执行产生的微任务全部执行之后,第二轮循环也就结束了。

执行结果:

golb1
glob1_promise
glob2_promise
glob1_nextTick
glob2_nextTick
glob1_then
glob2_then
timeout1
timeout1_promise
timeout1_nextTick
timeout1_then
timeout2
timeout2_promise
timeout2_nextTick
timeout2_then
immediate1
immediate1_promise
immediate1_nextTick
immediate1_then
immediate2
immediate2_promise
immediate2_nextTick
immediate2_then

注意:

1. 在队列中,先遇到的宏任务的队列在前面,后面所以该类型的宏任务都进入这个队列,都先执行,无论在多么后面。

2. 宏任务是一个一个的执行,同一轮循环不可以同时执行多个宏任务,只有在队列中的比如第一个宏任务全部执行完成,才会执行第二个宏任务

3. 微任务也是如此

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值