microtask queue指令优先级是否高于根级指令?JS异步顺序疑问
核心原因
你的推断错误源于对async函数执行机制的常见误解:调用async函数时,函数体从开头到第一个await/return/抛出错误位置的所有代码,都是同步执行的,并不会把整个函数直接丢进微任务队列。
逐行拆解你这段代码的执行流程
- 首先执行最外层的
run():- 同步打印
calling async func,碰到await func(),此时暂停run的执行,把await后面的console.log('done')注册为微任务,转去同步执行func()。
- 同步打印
- 进入
func执行:
2. 因为是async函数,开头没有await,所以同步打印async func called,接下来执行anotherAsync()调用,和调用普通同步函数没有区别,直接进入anotherAsync内部执行。 - 进入
anotherAsync执行:
3. 这个async函数内部全程没有await,所以整个函数体全部同步跑完:先打印Another async called,执行完10w次的空循环,再打印Another async finished,最后返回一个状态为fulfilled的Promise,退出函数回到func的调用位置。 - 回到
func继续执行:
4. 由于你调用anotherAsync()时没有加await,引擎不会等待它返回的Promise,直接往下同步执行,打印async func finished。此时func执行完毕,返回的Promise状态为fulfilled,之前await func()挂起的微任务进入队列。 - 当前调用栈清空,开始执行微任务队列:
5. 执行之前挂起的run后续代码,打印done,流程结束。
对你的猜想的纠正
不存在“await外层func会隐式await内部未加await的anotherAsync”的规则,引擎也不会特殊优先处理同作用域指令,你看到的顺序纯粹是因为async函数开头的代码是同步执行的。
你可以做个验证:给anotherAsync加一行await,代码如下:
const anotherAsync = async () => { console.log('Another async called'); await Promise.resolve(); // 新增这行,触发微任务分割 for (let i=0; i<=100000; i++) { } console.log('Another async finished'); };
此时运行结果就会变成:
calling async func async func called Another async called async func finished done Another async finished
这时候anotherAsync执行到新增的await位置时,会把await后面的所有代码注册为微任务,先跳出函数回到func继续执行后续逻辑,等调用栈空、前面的微任务(打印done)执行完之后,才会回来跑anotherAsync剩下的代码。
记住一个简单判断规则:只有async函数中
await后面的代码、以及async函数返回后挂载的then/catch/finally回调才会进入微任务队列,函数开头到第一个await之前的逻辑,永远是调用时同步执行的。
内容的提问来源于stack exchange,提问作者Amanur Rahman
相关产品推荐
相关产品推荐

