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

这是高级必会题。

相关推荐
前端一课1 小时前
第 28 题:手写 async/await(Generator 自动执行器原理)
前端·面试
前端一课1 小时前
第 33 题:浏览器渲染流程(Reflow 重排、Repaint 重绘、Composite 合成)*
前端·面试
前端一课1 小时前
前端面试第 34 题:事件循环(Event Loop)—— 必考高频题
前端·面试
前端一课1 小时前
第 26 题:Vue2 和 Vue3 的响应式原理有什么区别?为什么 Vue3 要用 Proxy 替代 defineProperty?
前端·面试
前端一课1 小时前
第 30 题:模块化原理(CommonJS vs ESModule)
前端·面试
前端一课1 小时前
第 31 题:Tree Shaking 原理与常见失效原因(高频 + 难点 + 面试必考)
前端·面试
前端一课1 小时前
第 27 题:Promise 实现原理(含手写 Promise)
前端·面试
前端一课1 小时前
第 32 题:深入理解事件循环(Event Loop)、微任务、宏任务(详细 + 难点 + 易错点)
前端·面试
前端一课2 小时前
【前端每天一题】🔥 第 25 题:什么是 Virtual DOM?它的优缺点是什么?Diff 算法是如何工作的?
前端·面试