首先亮出一道题目,自己先写出心中的答案
console.log('1');
setTimeout(function() {
console.log('2');
new Promise(function(resolve) {
console.log('4');
resolve();
}).then(function() {
console.log('5')
})
})
new Promise(function(resolve) {
console.log('7');
resolve();
}).then(function() {
console.log('8')
})
setTimeout(function() {
console.log('9');
new Promise(function(resolve) {
console.log('11');
resolve();
}).then(function() {
console.log('12')
})
})
首先从同步任务和异步任务来理解,同步任务就是 主线程来执行的时候立即能执行的代码,而异步任务就是当主线程执行到这个任务的时候,先把他放进队列里,等会来执行,本着先进先出(FIFO)的原则
接着从另一维度来理解 宏观任务和微观任务 ,除了Process.nextTick、Promise.then catch finally(注意不是单纯的Promise)、MutationObserver还包括V8的垃圾回收过程这几个微观任务,其他都是宏观任务
那上面题目的答案就可以很清楚的知道了,答案是 1 7 8 2 4 5 9 11 12
再来一题
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')
})
})
看到process.nextTick就知道是在node环境下运行的,事件的优先级 process.nextTick > promise.then > setTimeout > setImmediate
还有一点 node与浏览器的事件循环是有差异的:
浏览器环境下,microtask的任务队列是每个macrotask执行完之后执行;而在node.js中,microtask会在事件循环的各个阶段之间执行,也就是一个阶段执行完毕,就会去执行microtask队列的任务
这里需要注意的是 两个setTimeout在一个队列里同时运行,所以答案是:1 7 6 8 2 4 9 11 3 10 5 12 (node < 11)
这里还可以把第二个定时器设置为1s后执行 帮助理解
注意:node版本 >=11 和 11以下会有不同的表现
node >=11 :它会和浏览器的表现一致,一个定时器运行完立即执行相应的微任务 所以答案是 1 7 6 8 2 4 3 5 9 11 10 12
node < 11 :对于定时器的处理是,若第一个定时器任务出队列并执行完,发现队首的任务仍然是一个定时器,那么就将微任务暂时保存,直接去执行新的定时器任务,当新的定时器任务执行完后,再一一执行中途产生的微任务 所以答案是 1 7 6 8 2 4 9 11 3 10 5 12