关于Node.js中async/await执行顺序及事件循环交互机制的疑问
关于Node.js中async/await执行顺序及事件循环交互机制的疑问
咱们先把你的问题拆解透,核心是你对async/await和事件循环的交互逻辑有误解,一步步捋每个代码的执行过程,你就能明白为啥会出现那个输出顺序了。
先纠正一个核心误区
async函数不会一调用就被扔到事件队列里!它的执行逻辑是:调用后会同步执行函数体代码,直到遇到第一个await或者函数执行结束。只有await之后的代码,才会被放到微任务队列里,等当前主线程的同步代码全部执行完,再回来处理微任务。
分析你的第一个代码例子
先看你写的这段代码:
async function test2(){ console.log('3 test2 is being executed'); } async function test(){ console.log('2 test is being executed'); await test2(); console.log('4 test 2 was awaited'); } console.log('1 test is about to be called'); test(); console.log('5 test was called');
执行步骤全解析:
- 首先同步执行最外层的
console.log('1 test is about to be called');→ 输出1 test is about to be called - 调用
test():因为是async函数,同步执行函数体直到遇到await:- 先执行
console.log('2 test is being executed');→ 输出2 test is being executed - 接下来执行
await test2():先调用test2(),同样test2是async函数,同步执行它的函数体:- 执行
console.log('3 test2 is being executed');→ 输出3 test2 is being executed test2没有异步操作,执行完毕后返回一个状态为resolved的Promise(所有async函数只要正常结束,都会默认返回resolved Promise)
- 执行
- 现在
await这个resolved的Promise,此时会做两件事:- 把
await后面的代码(也就是console.log('4 test 2 was awaited');)放到微任务队列 - 暂停
test函数的执行,让出主线程
- 把
- 先执行
- 主线程回到最外层,继续执行同步代码
console.log('5 test was called');→ 输出5 test was called - 现在主线程的同步代码全部执行完了,开始处理微任务队列里的任务:取出刚才放进去的
console.log('4 test 2 was awaited');执行 → 输出4 test 2 was awaited
这就是为什么你最终得到的输出顺序是:
1 test is about to be called 2 test is being executed 3 test2 is being executed 5 test was called 4 test 2 was awaited
再看你编辑后的第二个例子
你后来加的这段代码:
async function test2(){ console.log('3 test2 is being executed'); } async function test(){ console.log('2 test is being executed'); await test2(); console.log('4 test 2 was awaited'); } console.log('1 test is about to be called'); let a=async ()=>{ await test(); } a(); console.log('5 test was called');
逻辑其实和第一个例子完全一致:
- 同步输出
1 test is about to be called - 调用
a(),同步执行到await test():- 调用
test(),同步执行到await test2():- 输出
2 test is being executed - 调用
test2()同步输出3 test2 is being executed,返回resolved Promise await test2()把test里的console.log('4...')放到微任务队列,暂停test
- 输出
await test()拿到的是test返回的resolved Promise,因为a函数里await之后没有代码,所以没有额外的微任务,但test里的微任务已经在队列里了
- 调用
- 主线程继续同步输出
5 test was called - 处理微任务队列,执行
console.log('4 test 2 was awaited');
所以输出顺序和第一个例子完全一样,本质还是await触发了微任务的添加,主线程优先跑完所有同步代码再处理微任务。
补充几个关键规则
- 没有
await的async函数=同步函数:如果async函数里没有await,那它会完全同步执行,不会触发任何微任务,就像你说的去掉await后输出顺序是1 2 3 4 5,因为test函数会从头到尾同步执行完,再跑最外层的console.log(5)。 await的本质是等待Promise状态:不管await的是async函数返回的Promise,还是手动创建的Promise,只要Promise是resolved状态,就会把后续代码扔到微任务队列;如果是pending状态,会等Promise变成resolved后再把后续代码扔到微任务队列。- 微任务队列的优先级高于宏任务:微任务(比如
await后续代码、Promise.then回调)会在主线程同步代码执行完后立即处理,而宏任务(比如setTimeout、setInterval)要等微任务队列清空后才会执行。
这样你就能完全明白为什么会出现这些执行顺序了,所有逻辑都是可预测的,核心就是抓住async函数的同步执行阶段,以及await对微任务队列的触发逻辑。
备注:内容来源于stack exchange,提问作者user2741831
相关产品推荐
相关产品推荐

