task/microtask执行顺序
先来一道面试题热身
问,执行顺序是什么?
Promise.resolve().then(function promise1() {
console.log('promise1');
})
setTimeout(function setTimeout1(){
console.log('setTimeout1')
Promise.resolve().then(function promise2() {
console.log('promise2');
})
}, 0)
setTimeout(function setTimeout2(){
console.log('setTimeout2')
}, 0)
分析一下运行过程:
- 循环1:
[task队列: script; microtask队列: []]
- 从task队列中取出script任务,推入栈中执行。
- promise1列为microtask,setTimeout1列为task,setTimeout2列为task。变为:
[task队列: [setTimeout1, setTimeout2]; microtask队列: [promise1] ] - script任务执行完毕,执行microtask checkpoint,取出microtask队列的promise1执行。此时微任务清空了
- 循环2:
[task队列: [setTimeout1, setTimeout2]; microtask队列: []]
- 从task队列中取出setTimeout1(因为task是队列遵循先进先出),推入栈中执行,将promise2列为microtask。
[task队列: [setTimeout2]; microtask队列: [ promise2 ]] - 执行microtask checkpoint,取出microtask队列的promise2执行, 此时microtask 清空。
- 循环3:
[task队列: [setTimeout2]; microtask队列: [ ]]
- 从task队列中取出setTimeout2,推入栈中执行。
- setTimeout2任务执行完毕,执行microtask checkpoint。
[task队列: []; microtask队列: []]所以,正确答案是
promise1
setTimeout1
promise2
setTimeout2
刚开始可能还会有一点困惑,困惑的点是基本上是同时添加了 宏、微任务,为什么微任务会在宏任务之前执行?
下面还有更详细的解释
setTimeout它只是一个task任务源,并不会立即执行,它只是将一个setTimeout任务插进task队列,得排到它,它里面的函数才会执行。Promise.then是microtask任务源,会将任务插进microtask队列。
Promise.resolve().then(function promise1() {
console.log('promise1');
})
setTimeout(function setTimeout1(){
console.log('setTimeout1')
}, 0)
以上面的例子来说,这两个仅仅是将相应的任务插进他们各自的队列中,此次event loop执行的task并不是setTimeout里的任务,setTimeout的任务排在下次循环了,当前只是插入task这个动作,还没轮到它执行。microtask队列的任务是会在当轮清空的,所以会看到promise1先于setTimeout1执行。并且上面两段代码顺序颠倒并不会影响结果。
关键点:每次执行一次宏任务结束后,会执行完所有的微任务并清空
for (const macroTask of macroTaskQueue) {
handleMacroTask();
for (const microTask of microTaskQueue) {
handleMicroTask(microTask);
}
}
js 的事件循环
知道了宏/微任务,再回到主题event-loop
- 宏任务
- 所有script代码
- setTimeout
- setInterval
- setImmediate(浏览器暂时不支持,只有IE10支持,具体可见MDN)
- I/O
- UI Rendering。
- 微任务
- Process.nextTick(Node独有)
- Promise
- Object.observe(废弃)
- MutationObserver
最主要是这个图,其他的还是看原文吧,参考文章第二篇讲的很透彻
参考文章:
从event loop规范探究javaScript异步及浏览器更新渲染时机
【THE LAST TIME】彻底吃透 JavaScript 执行机制