微任务和宏任务的执行顺序是面试中经常会被问到的问题,这里就来解析一下。
下面的代码中,打印的顺序是什么呢?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| console.log("script 1");
setTimeout(() => console.log("timeout 1"));
Promise.resolve().then(() => console.log("promise 1"));
Promise.resolve().then(() => setTimeout(() => console.log("timeout in promise")) );
Promise.resolve().then(() => console.log("promise 2"));
setTimeout(() => console.log("timeout 2"));
console.log("script 2");
|
答案是:
1 2 3 4 5 6 7
| [Log] script 1 [Log] script 2 [Log] promise 1 [Log] promise 2 [Log] timeout 1 [Log] timeout 2 [Log] timeout in promise
|
解析
JavaScript 是单线程的,它的任务调度是基于事件循环的。事件循环中有两种任务队列:微任务队列和宏任务队列。
timeout 中的回调函数会被放到宏任务队列中,而 promise 中的回调函数会被放到微任务队列中。
上面代码的的执行顺序如下:
宏任务有哪些
- script
- setTimeout
- setInterval
- setImmediate
- requestIdleCallback
微任务有哪些
- Promise 的 then 和 catch
- process.nextTick (Node.js 环境)
- MutationObserver (浏览器环境)
补充说明
宏任务 Macrotask 不是标准的术语, HTML Standard 中的定义是:Task。
Task 和 Macrotask 、 UI rendering 的执行顺序