标签:其他 一个 text 注册 记录 int class pen llb
最近在看《Node.js调试指南》的时候遇到有意思的几道题,是关于setTimeout, promise.then, process.nextTick, setImmediate的执行顺序。今天抽空记录下这道题的分析过程及背后的原理与知识点。
题目如下:
// 题目一:
setTimeout(()=>{
console.log('setTimeout')
},0)
setImmediate(()=>{
console.log('setImmediate')
})
// 题目二:
const promise = Promise.resolve()
promise.then(()=>{
console.log('promise')
})
process.nextTick(()=>{
console.log('nextTick')
})
// 题目三:
setTimeout (() => {
console.log(1)
},0)
new Promise((resolve,reject) => {
console.log(2)
for(let i = 0; i <10000; i++) {
i === 9999 && resolve()
}
console.log(3)
}).then(() => {
console.log(4)
})
console.log(5)
// 题目四
setInterval(()=>{
console.log('setInterval')
},100)
process.nextTick(function tick(){
process.nextTick(tick)
})
在分析这几道题之前先有必要了解下node.js的事件循环
我们可以简单理解Event Loop如下:
每个阶段都有一个FIFO的回调队列,当Event Loop执行到这个阶段时,就会从当前阶段的队列里拿出一个任务放到执行栈中执行,在队列任务清空或者执行的回调数量达到上限后,Event Loop就会进入下一个阶段
poll阶段主要有两个功能,如下所述:
一旦poll queue为空,则Event Loop将检查timers,如果有timer的时间到期,则Event Loop将回到timers阶段,然后执行timer queue
进入 check 阶段。
进入 closing 阶段。
检查是否有活跃的 handles(定时器、IO等事件句柄)。
通过上面的事件循环的介绍我们已经知道setTimeout setImmediate的执行机制,但是并没有介绍process.nextTick()和promise.then()。这里我们还需要知道宏任务与微任务的概念
宏任务是指Event Loop在每个阶段执行的任务
宏任务包括 script (整体代码),setTimeout, setInterval, setImmediate, I/O, UI renderin
微任务是指Event Loop在每个阶段之间执行的任务
微任务包括 process.nextTick, Promise,Object.observe,MutationObserver
宏任务与微任务执行顺序图
图中绿色小块表示Event Loop的各个阶段,执行的是宏任务,粉色箭头表示执行的是微任务
了解到这里我们再来分析上面的几道题
题目一的执行结果是:
setTimeout
setImmediate
//或者
setImmediate
setTimeout
为什么结果不确定呢?我们知道setTimeout的回调函数在timer阶段执行,setImmediate的回调函数在check阶段执行。但是从事件循环开始到timer阶段会消耗一定的时间,所以会出现两种情况:
题目二的执行结果是
nextTick
promise
这里虽然和process.nextTick一样,promise.then也将回调函数注册到microtask,但process.nextTick的microtask queue总是优先于promise的microtask queue执行的
题目三的执行结果是
2
3
5
4
1
Promise构造函数是同步执行的,所以先打印2,3,在打印5,接下来事件循环执行微任务执行promise.then的回调,打印4,然后进入下一个事件循环执行timer阶段的回调打印1
题目四的执行结果是
永远不会打印setInterval
process.nextTick会无限循环,将event loop阻塞在microtask阶段,导致event loop上其他macrotask阶段的回调函数没有机会执行
解决方法通常是用setImmediate代替process.nextTick.
在setImmediate内执行setImmedaite时会将immediate注册到下一次event loop的check阶段,这样其他macrotask就有机会执行
至此终于将node.js事件循环宏任务与微任务分析清楚了
解读setTimeout,promise.then,process.nextTick,setImmediate的执行顺序
标签:其他 一个 text 注册 记录 int class pen llb
原文地址:https://www.cnblogs.com/jesse131/p/11708233.html