事件环(Event Loop)
任务分类
-
宏任务:
- 脚本执行(顺序执行)
- UI 渲染
- 定时器(setTimeout)
- HTTP 请求
- 事件处理
- MessageChannel
- setImmediate
-
微任务:
- Promise.then
- MutationObserver
- process.nextTick
- queueMicrotask
执行顺序
- 执行一个宏任务
- 清空微任务队列
- 重复步骤 1 和 2
微任务与宏任务执行顺序示例
javascript
console.log(1);
async function async() {
console.log(2);
await console.log(3); // 相当于 Promise.resolve(console.log(3)).then(()=>{console.log(4)})
console.log(4); // 也会产生一个 then,在之后执行
}
setTimeout(() => {
console.log(5);
}, 0);
const promise = new Promise((resolve, reject) => {
console.log(6);
resolve(7);
});
promise.then((res) => {
console.log(res);
});
async();
console.log(8);
执行顺序分析
-
同步代码执行:
console.log(1)
→ 输出 1console.log(6)
→ 输出 6(Promise 构造函数中的同步代码)console.log(2)
→ 输出 2(async 函数开始执行)console.log(3)
→ 输出 3(await 后面的同步代码)console.log(8)
→ 输出 8
-
微任务队列:
- Promise.then 回调(输出 7)
- async 函数中 await 后的代码(输出 4)
-
宏任务队列:
- setTimeout 回调(输出 5)
最终输出顺序
1
6
2
3
8
7
4
5
执行过程详解
- 首先执行所有同步代码(1, 6, 2, 3, 8)
- 然后清空微任务队列:
- 执行 Promise.then 回调(7)
- 执行 async 函数中 await 后的代码(4)
- 最后执行宏任务队列中的 setTimeout 回调(5)
关键点说明
async/await
本质上是 Promise 的语法糖await
后面的代码会被包装成 Promise.then 回调- 微任务优先于宏任务执行
- 同步代码优先于异步代码执行
- Promise 构造函数中的代码是同步执行的
- setTimeout 是宏任务,即使延迟时间为 0
其他重要概念
- requestAnimationFrame:用于优化动画
- requestIdleCallback:用于空闲时间任务调度
- 进程间通信(IPC):多进程间通信机制