1. 基本的 async/await
和事件循环
console.log('1');async function asyncFunc() {console.log('2');await Promise.resolve();console.log('3');
}asyncFunc();console.log('4');
执行顺序:
- 打印
1
- 定义异步函数
asyncFunc
,但并不执行它。 - 调用
asyncFunc()
。- 打印
2
- 遇到
await
,所以asyncFunc
的后续代码(打印3
)被移到事件队列中等待。
- 打印
- 打印
4
- 所有同步代码执行完毕后,事件循环开始执行队列中的任务。
- 打印
3
- 打印
预期输出:
1
2
4
3
2. setTimeout
和 async/await
的结合
console.log('1');setTimeout(() => {console.log('2');
}, 0);async function asyncFunc() {console.log('3');await Promise.resolve();console.log('4');
}asyncFunc();console.log('5');
执行顺序:
- 打印
1
- 将
setTimeout
回调(打印2
)设置为在0毫秒后执行。但实际上,它会被放入宏任务队列,等待所有微任务完成。 - 定义异步函数
asyncFunc
,但并不执行。 - 调用
asyncFunc()
。- 打印
3
- 遇到
await
,所以asyncFunc
的后续代码(打印4
)被移到微任务队列中等待。
- 打印
- 打印
5
- 执行微任务队列中的任务(因为微任务的优先级高于宏任务)。
- 打印
4
- 打印
- 执行宏任务队列中的任务。
- 打印
2
- 打印
预期输出:
1
3
5
4
2
3. 嵌套的 async/await
console.log('1');async function firstAsync() {console.log('2');await secondAsync();console.log('3');
}async function secondAsync() {console.log('4');await Promise.resolve();console.log('5');
}firstAsync();console.log('6');
执行顺序:
- 打印
1
- 定义两个异步函数,但不执行。
- 调用
firstAsync()
。- 打印
2
- 调用
secondAsync()
。- 打印
4
- 遇到
await
,所以secondAsync
的后续代码(打印5
)被移到微任务队列中等待。
- 打印
firstAsync
的后续代码(打印3
)也被移到微任务队列中等待。
- 打印
- 打印
6
- 执行微任务队列中的任务。
- 打印
5
- 打印
3
- 打印
预期输出:
1
2
4
6
5
3
4. 多个异步函数
async function asyncOne() {console.log('1');await Promise.resolve();console.log('2');
}async function asyncTwo() {console.log('3');await Promise.resolve();console.log('4');
}console.log('5');asyncOne();
asyncTwo();console.log('6');
执行顺序:
- 定义两个异步函数,但不执行。
- 打印
5
- 调用
asyncOne()
。- 打印
1
- 遇到
await
,所以asyncOne
的后续代码(打印2
)被移到微任务队列中等待。
- 打印
- 调用
asyncTwo()
。- 打印
3
- 遇到
await
,所以asyncTwo
的后续代码(打印4
)被移到微任务队列中等待。
- 打印
- 打印
6
- 执行微任务队列中的任务。
- 打印
2
- 打印
4
- 打印
预期输出:
5
1
3
6
2
4
5. Promise 的基本行为
console.log('1');Promise.resolve().then(() => {console.log('2');
});console.log('3');
执行顺序:
- 打印
1
- 创建一个已解决的Promise,并在微任务队列中注册一个回调。
- 打印
3
- 当同步代码执行完成后,事件循环开始处理微任务队列,执行回调。
- 打印
2
预期输出:
1
3
2
6. setTimeout
与 Promise
的组合
console.log('1');setTimeout(() => {console.log('2');
}, 0);Promise.resolve().then(() => {console.log('3');
}).then(() => {console.log('4');
});console.log('5');
执行顺序:
- 打印
1
- 将
setTimeout
的回调加入宏任务队列 - 创建一个已解决的Promise,并在微任务队列中注册第一个回调
- 在第一个then的回调中,注册第二个then的回调到微任务队列
- 打印
5
- 事件循环开始处理微任务,首先执行第一个then的回调
- 打印
3
- 紧接着,事件循环处理第二个then的回调
- 打印
4
- 最后,事件循环处理宏任务队列
- 打印
2
预期输出:
1
5
3
4
2
7. 多个 async/await
的嵌套
console.log('1');async function outerAsync() {console.log('2');await innerAsync();console.log('3');
}async function innerAsync() {console.log('4');await new Promise(resolve => setTimeout(resolve, 0));console.log('5');
}outerAsync();console.log('6');
执行顺序:
- 打印
1
- 定义两个异步函数,但此时并未执行它们
- 调用
outerAsync()
- 打印
2
- 调用
innerAsync()
- 打印
4
- 遇到
setTimeout
,所以它的回调被加入宏任务队列 await
将后续代码(打印5
和outerAsync
中的打印3
)移至微任务队列- 打印
6
- 事件循环开始处理微任务,但在此之前,必须先完成
setTimeout
的回调**,必须要等里面完成才能完成外面** - 打印
5
- 继续执行
outerAsync
中的代码 - 打印
3
预期输出:
1
2
4
6
5
3
8. 多个微任务队列(这个不会)
console.log('1');async function firstFunc() {console.log('2');await Promise.resolve();console.log('3');
}async function secondFunc() {console.log('4');await Promise.resolve().then(() => {console.log('5');});console.log('6');
}firstFunc();
secondFunc();
console.log('7');
执行顺序:
- 打印
1
- 调用
firstFunc()
- 打印
2
await
使其后续代码(打印3
)移到微任务队列中- 调用
secondFunc()
- 打印
4
await
和then
使其后续代码(首先打印5
,然后打印6
)移到微任务队列中- 打印
7
- 事件循环开始处理微任务队列
- 打印
5
- 打印
3
- 打印
6
预期输出:
1
2
4
7
5
3
6
9. 复杂的async/await
与setTimeout
console.log('1');setTimeout(() => {console.log('2');
}, 0);async function asyncFunction() {console.log('3');await Promise.resolve();console.log('4');setTimeout(() => {