Promise 练习题
async 函数的执行顺序示例
let n = 0;
// async 如果里面没有await 就是一个普通函数
(async function a(num) {
console.log('1-', num); // 同步1 —— 1 0
// 先传参后加减
b(num++);
console.log('2-', num); // 同步5 —— 2 1
})(n);
async function b(num) {
console.log('3-', num); // 同步2 —— 3 0
// 先传参后加减
await c(num++); // 相当于 Promise.resolve().then(res => console.log('4-',++num);)
console.log('4-', ++num); // 微任务1 —— 4 1
}
async function c(num) {
console.log('5-', num); // 同步3 —— 5 0
// 异步任务 注册
setTimeout(() => {
console.log('6-', num); // 异步任务 —— 6 1
});
console.log('7-', ++num); // 同步4 —— 7 1
}
new Promise((resolve) => {
console.log('8-', n); // 同步6 —— 8 0
resolve(n);
}).then((res) => {
console.log('9-', n++); // 微任务2 —— 9 1
});
console.log('10-', n++ > n); // 同步7 —— 10 false
console.log('11-', n); // 同步8 —— 11 1
在这段代码中,涉及多个 async 函数、Promise 以及 setTimeout 的混合使用。以下是代码的执行顺序及其原因:
-
初始化变量
let n = 0;初始化变量n为0。
-
执行 IIFE (立即调用的异步函数)
(async function a(num) { ... })(n);立即调用异步函数a,传入当前的n值0。
-
函数
a执行console.log('1-', num);输出1- 0。- 调用
b(num++),传入当前num值0,然后num自增为1。 console.log('2-', num);输出2- 1。
-
函数
b执行console.log('3-', num);输出3- 0。- 调用
await c(num++),传入当前num值0,然后num自增为1。
-
函数
c执行console.log('5-', num);输出5- 0。- 设置一个
setTimeout,将在宏任务队列中注册一个回调,延迟执行console.log('6-', num);。 console.log('7-', ++num);先将num自增为1,然后输出7- 1。
-
继续执行函数
bawait c(num++)等待c函数执行完毕。由于c中没有返回Promise,默认返回undefined,因此继续执行后续代码。console.log('4-', ++num);将num自增为2,然后输出4- 2。此时,b函数的微任务完成。
-
执行
Promisenew Promise((resolve) => { ... }).then(res => { ... });创建一个新的Promise。console.log('8-', n);输出8- 0。resolve(n);立即解析Promise,将n的值0传递给下一个then。- 在微任务队列中注册
then回调,输出9- 1(因为n++后n变为1)。
-
同步代码继续执行
console.log('10-', n++ > n);计算0 > 1,结果为false,然后n自增为1。输出10- false。console.log('11-', n);输出11- 1。
-
处理微任务队列
- 先执行
b函数中console.log('4-', ++num);输出4- 2。 - 然后执行
Promise的then回调,输出9- 1。
- 先执行
-
处理宏任务队列
- 执行
setTimeout回调,输出6- 1。
- 执行
最终输出顺序:
1- 0
3- 0
5- 0
7- 1
8- 0
10- false
11- 1
4- 2
9- 1
6- 1
详细解释:
- 同步任务 按照代码顺序依次执行,输出
1- 0、3- 0、5- 0、7- 1、8- 0、10- false、11- 1。 - 微任务 包含
async函数中的await后的代码和Promise.then回调,先执行4- 2,然后执行9- 1。 - 异步任务 包含
setTimeout回调,最后执行6- 1。
关键点解析:
-
async函数的行为:- 如果
async函数内部没有await,则其行为类似于普通函数,所有同步代码立即执行。 - 一旦遇到
await,函数会暂停执行,等待await的 Promise 完成后再继续执行后续代码,这部分代码会作为微任务加入微任务队列中。
- 如果
-
Promise和setTimeout的区别:Promise的回调(如then)属于微任务,优先于宏任务执行。setTimeout的回调属于宏任务,会在所有微任务完成后执行。
-
变量自增操作的顺序:
num++是后缀自增,先传递当前值,再自增。++num是前缀自增,先自增,再传递新值。