// 基础异步函数,返回数字1
async function m1() {
return 1; // 自动包装为Promise.resolve(1)
}
// 中级异步函数,等待m1的结果并打印
async function m2() {
const n = await m1();
console.log(n); // 打印从m1获得的值
}
// 高级异步函数,等待m2的结果并尝试计算
async function m3() {
const n = await m2();
console.log(n * 2); // 尝试对m2的结果进行计算
}
// 第一次调用m3并附加then回调
m3().then((data) => {
console.log(data);
});
// 第二次直接调用m3
m3();
// 同步日志输出
console.log(3);
执行流程详解
执行阶段划分
-
同步执行阶段
- 执行所有同步代码
- 注册异步任务
-
微任务队列处理阶段
- 按顺序处理所有微任务
详细执行步骤
| 步骤 | 操作 | 说明 |
|---|---|---|
| 0 | 第一次调用m3() | 开始第一个异步调用链 |
| 1 | 解析m3()中的await m2() | 创建Promise并等待m2() |
| 2 | 进入m2(),解析await m1() | 创建Promise并等待m1() |
| 3 | m1()返回Promise.resolve(1) | 立即解析为值1 |
| 4 | 将console.log(1)加入微队列 | 来自m2()的await解析 |
| 5 | m2()返回未完成的Promise | 等待console.log执行 |
| 6 | m3()继续等待m2()完成 | |
| 7 | 第二次调用m3() | 开始第二个异步调用链 |
| 8 | 重复步骤1-6 | 创建第二个调用链 |
| 9-13 | 类似第一个调用链的处理 | |
| 14 | 执行console.log(3) | 同步代码优先执行 |
| 15-16 | 执行两个console.log(1) | 从微队列取出并执行 |
| 17-18 | 将两个console.log(NaN)加入微队列 | 因为m2()返回undefined |
| 19-20 | 执行两个console.log(NaN) | undefined*2=NaN |
| 21 | 将console.log(undefined)加入微队列 | 来自第一个m3()的then回调 |
| 22 | 执行console.log(undefined) | m3()没有返回值 |
关键概念说明
-
async函数行为:
- 总是返回Promise
- return值会被自动包装为Promise.resolve()
- 无return时默认返回Promise.resolve(undefined)
-
await机制:
- 暂停当前async函数执行
- 等待右侧表达式解析完成
- 将后续代码包装为微任务
-
执行顺序规则:
- 同步代码 > 微任务 > 宏任务
- 多个微任务按注册顺序执行
最终输出结果
3
1
1
NaN
NaN
undefined
问题分析
-
NaN产生原因:
- m2()没有返回值,导致n为undefined
- undefined * 2 = NaN
-
undefined输出:
- m3()没有返回值
- then回调收到的data是undefined
-
执行顺序保证:
- console.log(3)最先执行(同步代码)
- 然后是微任务队列中的日志
- 最后是then回调的日志