跳到主要内容

题型

一、await 普通值


考察点:

  1. await 非thenable: 会立即向微任务队列添加一个微任务then

1.1 问题

async function async1() {
console.log("1");
await 1;
console.log("2");
}

async1();

console.log("3");

Promise.resolve()
.then(() => {
console.log("4");
})
.then(() => {
console.log("5");
})
.then(() => {
console.log("6");
});


// 结果: 1 3 2 4 5 6

1.2 解释

二、await thenable 值


考察点:

  1. await thenable: 需要等待一个 then 的时间之后, 加入微任务队列

2.1 问题

async function async1() {
console.log("1");
await {
then(cb) {
cb();
},
};
console.log("2");
}

async1();

console.log("3");

Promise.resolve()
.then(() => {
console.log("4");
})
.then(() => {
console.log("5");
})
.then(() => {
console.log("6");
});

// 结果: 1 3 4 2 5 6

2.2 解释

三、await Promise 值


考察点

  1. await Promise: 需要等待一个 then 的时间之后, 加入微任务队列

3.1 问题

async function async1() {
console.log("1");
await new Promise((resolve,reject)=>{
resolve();
})
console.log("2");
}

async1();

console.log("3");

Promise.resolve()
.then(() => {
console.log("4");
})
.then(() => {
console.log("5");
})
.then(() => {
console.log("6");
});

// 结果: 1 3 4 2 5 6

3.2 解释

四、async 没有返回值


考察点:

  1. async 默认返回 undefined

  2. await 表达式; 这一语句是同步的

  3. await 表达式; 之后的语句会进行封装统一加入到微任务队列

  4. async 函数如果返回的是普通值, 那么会立即更新为成功状态

4.1 问题

async function async1() {
console.log("1");
await async2();
console.log("2");
}

async function async2() {
console.log("3");
}

console.log("5");

setTimeout(() => {
console.log("6");
}, 0);

async1();

new Promise((resolve) => {
console.log("7");
resolve();
})
.then(() => {
console.log("8");
})
.then(() => {
console.log("9");
})
.then(() => {
console.log("10");
});

console.log("11");

// 结果: 5 1 3 7 11 2 8 9 10 6

4.2 解释

  1. 事件循环从宏任务 macrosTack 队列开始。此时在宏任务队列中, 只有一个script(整体代码)任务。从宏任务队列中取出一个任务来执行先执行同步代码

  2. 首先执行 console.log("5");, 输出 5

  3. 执行setTimeout, 将setTimeout的回调函数放入到macroTask队列

  4. 接着执行async1函数,输出1

  5. 遇到await async2();, 同步执行async2()

  6. 执行async2() 函数中的 console.log("3");, 输出3

  7. 由于async2() 函数返回的是字符串, 立即更新成功状态。那么 await async2(); 之后的代码 console.log("2"); 会整体作为一个微任务, 立即加入到微任务microTask队列

  8. 遇到new Promise(), 同步执行console.log("7"); , 输出7

  9. .then()依次按序加入到微任务microTask队列

  10. 执行同步代码console.log("11");, 输出11

  11. script 宏任务执行完毕,开始检查微任务microTask队列, 依次执行, 清空微任务队列

  12. 执行微任务一console.log("2");, 输出2; 执行微任务二console.log("8");, 输出8; 执行微任务三console.log("9");, 输出9; 执行微任务四console.log("10");, 输出10

  13. 按序从宏任务队列macroTask中去一个任务放入主栈执行, 执行console.log("6");, 输出6

五、async 返回普通值


考察点:

  1. await 表达式; 这一语句是同步的

  2. await 表达式; 之后的语句会进行封装统一加入到微任务队列

  3. async 函数如果返回的是普通值, 那么会立即更新为成功状态

5.1 问题

async function async1() {
console.log("1");
await async2();
console.log("2");
}

async function async2() {
console.log("3");
return "async2 函数";
}

console.log("5");

setTimeout(() => {
console.log("6");
}, 0);

async1();

new Promise((resolve) => {
console.log("7");
resolve();
})
.then(() => {
console.log("8");
})
.then(() => {
console.log("9");
})
.then(() => {
console.log("10");
});

console.log("11");

// 结果: 5 1 3 7 11 2 8 9 10 6

5.2 解释

  1. 事件循环从宏任务 macrosTack 队列开始。此时在宏任务队列中, 只有一个script(整体代码)任务。从宏任务队列中取出一个任务来执行先执行同步代码

  2. 首先执行 console.log("5");, 输出 5

  3. 执行setTimeout, 将setTimeout的回调函数放入到macroTask队列

  4. 接着执行async1函数,输出1

  5. 遇到await async2();, 同步执行async2()

  6. 执行async2() 函数中的 console.log("3");, 输出3

  7. 由于async2() 函数返回的是字符串, 立即更新成功状态。那么 await async2(); 之后的代码 console.log("2"); 会整体作为一个微任务, 立即加入到微任务microTask队列

  8. 遇到new Promise(), 同步执行console.log("7"); , 输出7

  9. .then()依次按序加入到微任务microTask队列

  10. 执行同步代码console.log("11");, 输出11

  11. script 宏任务执行完毕,开始检查微任务microTask队列, 依次执行, 清空微任务队列

  12. 执行微任务一console.log("2");, 输出2; 执行微任务二console.log("8");, 输出8; 执行微任务三console.log("9");, 输出9; 执行微任务四console.log("10");, 输出10

  13. 按序从宏任务队列macroTask中去一个任务放入主栈执行, 执行console.log("6");, 输出6

六、async 返回 thenable


考察点:

  1. await 表达式; 这一语句是同步的

  2. await 表达式; 之后的语句会进行封装统一加入到微任务队列

  3. async 函数如果返回的是then(), 那么会延迟1then()时间后更新为成功状态

6.1 问题

async function async1() {
console.log("1");
await async2();
console.log("2");
}

async function async2() {
console.log("3");
return {
then(cb) {
cb();
},
};
}

console.log("5");

setTimeout(() => {
console.log("6");
}, 0);

async1();

new Promise((resolve) => {
console.log("7");
resolve();
})
.then(() => {
console.log("8");
})
.then(() => {
console.log("9");
})
.then(() => {
console.log("10");
});

console.log("11");

// 结果: 5 1 3 7 11 8 2 9 10 6

6.2 解释

  1. 事件循环从宏任务 macrosTack 队列开始。此时在宏任务队列中, 只有一个script(整体代码)任务。从宏任务队列中取出一个任务来执行先执行同步代码

  2. 首先执行 console.log("5");, 输出 5

  3. 执行setTimeout, 将setTimeout的回调函数放入到macroTask队列

  4. 接着执行async1函数,输出1

  5. 遇到await async2();, 同步执行async2()

  6. 执行async2() 函数中的 console.log("3");, 输出3

  7. 由于async2() 函数返回的是thenable, 延迟1then()后更新成功状态。那么 await async2(); 之后的代码 console.log("2"); 会整体作为一个微任务, 延迟1then()后加入到微任务microTask队列

  8. 遇到new Promise(), 同步执行console.log("7"); , 输出7

  9. .then()依次按序加入到微任务microTask队列。此时微任务队列为[console.log("8");,console.log("2");,console.log("9");,console.log("10");]

  10. 执行同步代码console.log("11");, 输出11

  11. script 宏任务执行完毕,开始检查微任务microTask队列, 依次执行, 清空微任务队列

  12. 执行微任务一console.log("8");, 输出8; 执行微任务二console.log("2");, 输出2; 执行微任务三console.log("9");, 输出9; 执行微任务四console.log("10");, 输出10

  13. 按序从宏任务队列macroTask中去一个任务放入主栈执行, 执行console.log("6");, 输出6

七、async 返回 Promise


考察点:

  1. await 表达式; 这一语句是同步的

  2. await 表达式; 之后的语句会进行封装统一加入到微任务队列

  3. async 函数如果返回的是Promise, 那么会延迟2then()时间后更新为成功状态

7.1 问题

async function async1() {
console.log("1");
await async2();
console.log("2");
}

async function async2() {
console.log("3");
return new Promise((resolve, reject) => {
resolve();
console.log("4");
});
}

console.log("5");

setTimeout(() => {
console.log("6");
}, 0);

async1();

new Promise((resolve) => {
console.log("7");
resolve();
})
.then(() => {
console.log("8");
})
.then(() => {
console.log("9");
})
.then(() => {
console.log("10");
});

console.log("11");


// 结果: 5 1 3 4 7 11 8 9 2 10 6

7.2 解释

  1. 事件循环从宏任务 macrosTack 队列开始。此时在宏任务队列中, 只有一个script(整体代码)任务。从宏任务队列中取出一个任务来执行先执行同步代码

  2. 首先执行 console.log("5");, 输出 5

  3. 执行setTimeout, 将setTimeout的回调函数放入到macroTask队列

  4. 接着执行async1函数,输出1

  5. 遇到await async2();, 同步执行async2()

  6. 执行async2() 函数中的 console.log("3");, 输出3

  7. 由于async2() 函数返回的是Promise, 延迟2then()后更新成功状态。那么 await async2(); 之后的代码 console.log("2"); 会整体作为一个微任务, 延迟2then()后加入到微任务microTask队列

  8. 遇到new Promise(), 同步执行console.log("7"); , 输出7

  9. .then()依次按序加入到微任务microTask队列。此时微任务队列为[console.log("8");,console.log("9");,console.log("2");,console.log("10");]

  10. 执行同步代码console.log("11");, 输出11

  11. script 宏任务执行完毕,开始检查微任务microTask队列, 依次执行, 清空微任务队列

  12. 执行微任务一console.log("8");, 输出8; 执行微任务二console.log("9");, 输出9; 执行微任务三console.log("2");, 输出2; 执行微任务四console.log("10");, 输出10

  13. 按序从宏任务队列macroTask中去一个任务放入主栈执行, 执行console.log("6");, 输出6

参考资料


你不知道的 async、await 魔鬼细节