我是这样理解EventLoop的 (3)

重点:如上图所,在Node.js中,一次宏任务可以认为是包含上述6个阶段、微任务microtask会在事件循环的各个阶段之间执行,也就是一个阶段执行完毕,就会去执行microtask队列的任务。

2、process.nextTick()

  在第二节中就了解到,process.nextTick()属于微任务,但是这里需要重点提及下:

process.nextTick()虽然它是异步API的一部分,但未在图中显示。因为process.nextTick()从技术上讲,它不是事件循环的一部分;

当每个阶段完成后,如果存在 nextTick,就会清空队列中的所有回调函数,并且优先于其他 microtask 执行(可以理解为微任务中优先级最高的)

3、实例分析

  老规矩,线上代码:

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') }) }) console.log('13')

将代码的执行分区进行解释

在这里插入图片描述


分析:如下图草稿所示,左上角标a为宏任务队列,左上角标i为微任务队列,左上角标t为timers阶段队列,左上角标p为nextTick队列同一层循环中,本层宏任务先执行,再执行微任务;本层宏任务中的非微任务异步代码块作为下层循环的宏任务进入下次循环,如此循环执行:

在这里插入图片描述

1、整体代码可以看做宏任务,同步代码直接进入主线程执行,输出1,7,13,接着执行同层微任务且nextTick优先执行输出6,8;

2、二层中宏任务中只存在setTimeout,两个setTimeout代码块依次进入6阶段中的timer阶段以t1、t2进入队列;代码等价于:

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

3、setTimeout中的同步代码立即执行输出2,4,9,11,nextTick和Pormise.then进入微任务执行输出3,10,5,12;

4、二层中不存在6阶段中的其他阶段,循环完毕,最终输出结果为:1->7->13->6->8->2->4->9->11->3->10->5->12;

4、当堂小考 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') setTimeout(function() { console.log('6'); process.nextTick(function() { console.log('7'); }) new Promise(function(resolve) { console.log('8'); resolve(); }).then(function() { console.log('9') }) }) }) }) process.nextTick(function() { console.log('10'); }) new Promise(function(resolve) { console.log('11'); resolve(); }).then(function() { console.log('12') setTimeout(function() { console.log('13'); process.nextTick(function() { console.log('14'); }) new Promise(function(resolve) { console.log('15'); resolve(); }).then(function() { console.log('16') }) }) }) setTimeout(function() { console.log('17'); process.nextTick(function() { console.log('18'); }) new Promise(function(resolve) { console.log('19'); resolve(); }).then(function() { console.log('20') }) }) console.log('21') 五、总结

  浏览器和Node环境下,microtask 任务队列的执行时机不同:Node 端,microtask 在事件循环的各个阶段之间执行;浏览器端,microtask 在事件循环的 macrotask 执行完之后执行;

参考借鉴

深入理解 JavaScript Event Loop

这一次,彻底弄懂 JavaScript 执行机制

【THE LAST TIME】彻底吃透 JavaScript 执行机制

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyjjzg.html