宏任务和微任务
事件循环概述
事件循环(Event Loop)是JavaScript 引擎用来处理异步任务的一种机制,主要由主线程和任务队列组成。
js代码可分为同步任务
和异步任务
,同步任务
由主线程顺序执行,而异步任务
由异步进程处理后将回调函数放入任务队列,等待主线程读取调用。
主线程执行完当前的同步任务后,不断读取调用任务队列的回调函数,直到清空任务队列,该循环机制称为事件循环。
宏任务和微任务
异步任务分为 宏任务(Macro task) 和 微任务(micro task)
宏任务 (Macrotask) | 微任务 (Microtask) |
---|---|
script(整体代码块) | Promise.then/catch/finally |
setTimeout | async await |
setInterval | queueMicrotask |
setImmditate | MutationObserver(监听器) |
I/O,事件队列 | process.nextTick |
requestAnimationFrame(争议) |
宏任务:代表着 JavaScript 运行时环境中的一个主要工作单元,类似一个载体。
微任务:运行依托于宏任务,执行优先级高于宏任务。
注:代码执行优先级为同步代码 > 微任务 > 宏任务
代码执行过程如下:
- 进入宏任务
- 执行所有同步代码,将异步任务放入对应的任务队列
- 执行微任务队列中的回调函数
- 从宏任务队列中取出下一个宏任务
- 重复上述步骤
举个栗子
async function test() {
await console.log(8);
console.log(9);
}
console.log(1);
test();
setTimeout(() => {
console.log(2);
}, 0);
new Promise((resolve) => {
console.log(4);
resolve();
console.log(5);
}).then(() => {
console.log(6);
});
console.log(7);
执行顺序:
1--> 8--> 4--> 5--> 7--> 9--> 6--> 2
注:红色框内代表立即执行的同步代码
解析:
- 同步代码:
await
右侧代码console.log(8)
属于同步代码,Promise
内部的console.log(4)
和console.log(5)
也属于同步代码。主线程按代码顺序执行,因此1、8、4、5、7先打印 - 微任务:
await
下面的代码console.log(9)
放入微任务队列中,Promise.then
中的代码console.log(6)
放入微任务队列中。按照先进先出
的顺序,打印9、6 - 宏任务:最后执行宏任务中的代码
console.log(2)
,打印2
再举个栗子
async function test() {
await console.log(1);
console.log(2);
}
console.log(3);
test();
setTimeout(() => {
console.log(4);
}, 0);
new Promise((resolve) => {
console.log(5);
resolve();
}).then(async () => {
await console.log(6);
console.log(7);
}).then(() => {
console.log(8);
});
new Promise((resolve) => {
console.log(9);
resolve();
}).then(() => {
console.log(10);
setTimeout(() => {
console.log(11);
});
}).then(() => {
console.log(12);
});
执行顺序:
3--> 1--> 5--> 9--> 2--> (6--> 10--> 7--> 12--> 8)--> 4--> 11
关键在于微任务的执行顺序,即两个Promise.then
的执行。因此我们对微任务入队和执行的轮次进行解析
// 取名为Pormise1
new Promise((resolve) => {
console.log(5);
resolve();
}).then(async () => {
await console.log(6);
console.log(7);
}).then(() => {
console.log(8);
});
// 取名为Pormise2
new Promise((resolve) => {
console.log(9);
resolve();
}).then(() => {
console.log(10);
setTimeout(() => {
console.log(11);
});
}).then(() => {
console.log(12);
});
注:红色框内代表立即执行的同步代码,绿色框内代表需放入微任务队列的微任务代码
转载自:https://juejin.cn/post/7381476230775898166