一、(事件循环)
这段代码涉及 同步任务、微任务(Microtasks)、宏任务(Macrotasks) 以及 async/await
的执行机制。我们可以通过分析事件循环(Event Loop)的运作方式来解释代码的输出顺序。
代码执行步骤分析
1. 同步任务
同步任务会立即执行,按照代码顺序依次输出:
console.log('script start');
→ 输出script start
。- 调用
asycn1()
,进入asycn1
函数:console.log('async1 start');
→ 输出async1 start
。- 遇到
await async2()
,调用async2
函数:console.log('async2');
→ 输出async2
。
await
会让出主线程,将async1
函数剩余部分(console.log('async1 end');
)放入微任务队列。
- 执行
new Promise
:console.log('promise1');
→ 输出promise1
。resolve()
将.then
中的回调(console.log('promise2');
)放入微任务队列。
console.log('script end');
→ 输出script end
。
此时,同步任务执行完毕,输出顺序为:
script start
async1 start
async2
promise1
script end
2. 微任务
微任务会在当前 JavaScript 任务(同步任务)执行完毕后立即执行。微任务队列中的任务按顺序执行:
await async2()
后面的代码(console.log('async1 end');
)被放入微任务队列。Promise.resolve().then(() => console.log('promise2'));
被放入微任务队列。
微任务队列的执行顺序:
console.log('async1 end');
→ 输出async1 end
。console.log('promise2');
→ 输出promise2
。
此时,微任务执行完毕,输出顺序为:
async1 end
promise2
3. 宏任务
宏任务会在当前事件循环的后续阶段执行。宏任务队列中的任务按顺序执行:
setTimeout(() => { console.log('setTimeout'); }, 0);
被放入宏任务队列。
宏任务队列的执行顺序:
console.log('setTimeout');
→ 输出setTimeout
。
最终输出顺序
综合以上分析,代码的完整输出顺序为:
script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout
详细步骤总结
步骤 | 任务类型 | 代码行为 | 输出结果 |
---|---|---|---|
1 | 同步任务 | console.log('script start'); | script start |
2 | 同步任务 | asycn1() → console.log('async1 start'); | async1 start |
3 | 同步任务 | await async2() → console.log('async2'); | async2 |
4 | 微任务 | await 后面的代码放入微任务队列 | - |
5 | 同步任务 | new Promise → console.log('promise1'); | promise1 |
6 | 微任务 | .then 回调放入微任务队列 | - |
7 | 同步任务 | console.log('script end'); | script end |
8 | 微任务 | 执行微任务队列:console.log('async1 end'); | async1 end |
9 | 微任务 | 执行微任务队列:console.log('promise2'); | promise2 |
10 | 宏任务 | 执行宏任务队列:console.log('setTimeout'); | setTimeout |
关键点总结
- 同步任务:立即执行,按照代码顺序输出。
- 微任务:
- 包括
Promise.then
和await
后面的代码。 - 在当前 JavaScript 任务结束后立即执行。
- 包括
- 宏任务:
- 包括
setTimeout
、setInterval
等。 - 在微任务执行完毕后执行。
- 包括
async/await
:await
会让出主线程,将后面的代码放入微任务队列。async
函数返回一个Promise
。