第 28 题:async / await 的原理是什么?为什么说它是 Promise 的语法糖?(详细版)

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:

  1. 执行 await 后面表达式,得到一个 Promise(如果不是,会自动包装成 Promise.resolve)
  2. 暂停当前 async 函数
  3. 把 await 后面的代码放到微任务队列
  4. 等待 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(实现自动执行器) 吗?

这是高级必会题。

相关推荐
无我Code1 天前
前端-2025年末个人总结
前端·年终总结
文刀竹肃1 天前
DVWA -SQL Injection-通关教程-完结
前端·数据库·sql·安全·网络安全·oracle
LYFlied1 天前
【每日算法】LeetCode 84. 柱状图中最大的矩形
前端·算法·leetcode·面试·职场和发展
Bigger1 天前
Tauri(21)——窗口缩放后的”失焦惊魂”,游戏控制权丢失了
前端·macos·app
Bigger1 天前
Tauri (20)——为什么 NSPanel 窗口不能用官方 API 全屏?
前端·macos·app
bug总结1 天前
前端开发中为什么要使用 URL().origin 提取接口根地址
开发语言·前端·javascript·vue.js·html
zwjapple1 天前
全栈开发面试高频算法题
算法·面试·职场和发展
程序员爱钓鱼1 天前
Node.js 编程实战:Redis缓存与消息队列实践
后端·面试·node.js
一招定胜负1 天前
网络爬虫(第三部)
前端·javascript·爬虫
Shaneyxs1 天前
从 0 到 1 实现CloudBase云开发 + 低代码全栈开发活动管理小程序(13)
前端