JavaScript 宏观和微观任务
前言
定义:宿主机(浏览器)发起的任务称为宏观任务,JavaScript 引擎发起的任务称为微观任务。
在宏观任务中,JavaScript 的 Promise 还会产生异步代码,JavaScript 必须保证这些异步代码在一个宏观任务中完成,因此,每个宏观任务中又包含了一个微观任务队列。
Promise 永远在队列尾部添加微观任务。setTimeout 等宿主 API,则会添加宏观任务。
代码验证
先来看下面 Promise 与 setTimeout 混用的这段代码,通过 setTimeout 执行 console.log(‘d’),通过 Promise 延迟5秒执行 console.log(‘c’)。
第 9 行 while 循环 形成一个自旋锁 确保5秒之后执行 console.log(‘c’)
1 | setTimeout(() => console.log('d'), 0) |
从语义上感觉 c 应该是最后被打印的。但实际打印顺序是a b c d,无论 setTimeout 是放在顶部还是底部都不会改变打印顺序。
分析
因为 Promise 产生的是 JavaScript 引擎内部的微任务,而 setTimeout 是浏览器 API,它产生宏任务。setTimeout 把整段代码分隔成 2 个宏任务。
2-12 行为第 1 个宏任务(优先执行),setTimeout 中的 console.log(‘d’) 为第 2 个宏任务,在第 1 个宏任务执行完之后再执行。
所以这也很好的解释了为何 d 总是最后被打印。