async / await 的原理是什么?为什么说它是 Promise 的语法糖?(详细版)**
async/await 是现代 JS 异步编程的核心,面试官喜欢问:
- async 到底返回什么?
- await 是如何"暂停"的?
- async/await 和 Promise 的关系是什么?
- async/await 为什么会让人觉得像同步?
我们逐条说明。
一、async 的本质
任何 async 函数的返回值一定是 Promise。------ 无条件!
例子:
csharp
async function demo() {
return 123;
}
等价于:
javascript
function demo() {
return Promise.resolve(123);
}
如果 async 内部抛出异常:
javascript
async function demo() {
throw new Error("err");
}
等价于:
javascript
function demo() {
return Promise.reject(new Error("err"));
}
二、await 的本质
await 会暂停 async 函数的执行,把后续代码加入微任务队列(Promise.then)。
简化理解:
ini
let x = await foo();
等价于:
ini
foo().then(result => {
x = result;
// 恢复 async 函数执行
});
但关键差别是:
⚠ JS 主线程没有暂停,是 async 函数暂停了
主线程继续执行后面的代码。
三、await 的执行机制(最重要)
每次遇到 await:
- 执行 await 后面表达式,得到一个 Promise(如果不是,会自动包装成 Promise.resolve)
- 暂停当前 async 函数
- 把 await 后面的代码放到微任务队列
- 等待 Promise 完成后恢复执行
四、async/await = Generator + 自动执行器(自动 yield)
ES 语义上:
async/await 是 Generator + co 库的语法糖。
比如:
javascript
async function test() {
let r = await foo();
console.log(r);
}
等价于 Generator:
javascript
function* test() {
let r = yield foo();
console.log(r);
}
加上执行器(自动执行 Generator):
scss
co(test);
所以:
await 就是自动 yield
async 就是自动执行 Generator 的包装器
五、为什么 async/await 写起来像同步?
因为:
- JS 主线程继续执行
- async 函数内部挂起(暂停)
- 恢复时继续从上次断点执行
让代码结构看起来是同步顺序:
ini
const a = await step1();
const b = await step2(a);
const c = await step3(b);
但本质上:
- 每个 await 都是把后面的逻辑放入微任务队列
- 整个过程是异步非阻塞的
六、async/await 的错误处理方式
try/catch :
javascript
try {
const data = await fetchData();
} catch (err) {
console.log(err);
}
相当于:
scss
fetchData()
.then(...)
.catch(...)
区别是:
✔ 错误流程和同步代码一样易读
✔ async/await 更适合复杂逻辑
七、最常考示例:输出顺序题
例题:
javascript
async function test() {
console.log(1);
await Promise.resolve();
console.log(2);
}
console.log(3);
test();
console.log(4);
输出顺序:
bash
3 (主线程)
1 (执行 test 的同步部分)
4 (主线程继续)
2 (await 后的微任务)
为什么?
- await 将后续放入微任务
- 所以 2 最后执行
八、20 秒面试背诵版
async 函数会返回一个 Promise;函数内部抛错会等于返回 reject。
await 会暂停 async 函数,把后续逻辑加入微任务队列,等待 Promise 完成后继续执行。
本质上 async/await 是 Promise + Generator 的语法糖,让异步代码以同步写法表达。
要继续 第 34 题:手写一个 async/await(实现自动执行器) 吗?
这是高级必会题。