第 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(实现自动执行器) 吗?

这是高级必会题。

相关推荐
Csvn1 小时前
并发模式:让渲染学会排队、插队和让路
前端
可乐鸡翅yeah_1 小时前
新手梳理:M3U8 线上问题,哪些是前端锅,哪些是后端锅
前端·ios·音视频·实时音视频·m3u8·音视频在线播放
Flynt1 小时前
Linear 用 1000 个 PR 换掉 styled-components,我写了 200 个按钮,把这笔账复现了一遍
前端·css·preact
JavaGuide2 小时前
NVIDIA 又开源了!这次给 AI Agent 加上权限管控
前端·后端
excel3 小时前
prisma 如何处理数据库竞态
前端·数据库·后端
莪_幻尘4 小时前
Skill 体检:30 个 Skill 全凭感觉?体检器先自曝了 8 个“假 0 分
前端·人工智能·llm
风骏时光牛马4 小时前
AI模型综合能力评测:性能、指令遵循与多场景实测对比
前端
Frag0ut4 小时前
Chrome与Chromium内核浏览器在Windows 11上的新特性全景解析
前端·chrome·windows·web安全·chromium·gemini ai·playready drm
此时不提桶,更待何时4 小时前
05-03-B-ClickHouse与OLAP面试与生产事故实战
clickhouse·面试·nosql
hiahiahia1235 小时前
实现完整 Tool Dispatcher
开发语言·前端