🚀把 async/await 拆成 4 块乐高!面试官当场鼓掌👏

面试官:"说说 async/await 的原理。"

你:"就是语法糖。"

面试官:"展开讲讲。"

你:"......"

别急,今天我们把 async/await 拆成 4 块乐高: Promise → Generator → 自执行器 → async/await。拼完就再也不会卡壳。


一、前菜:Promise 的"链式地狱"

js 复制代码
function fetchUser(id) {
  return fetch(`/user/${id}`).then(r => r.json());
}

fetchUser(1)
  .then(user => fetch(`/order/${user.lastOrder}`))
  .then(order => fetch(`/detail/${order.id}`))
  .then(console.log)
  .catch(console.error);

缺点:横向金字塔、错误处理分散、变量作用域混乱。

需求:像同步那样写异步 ------ async/await 登场!


二、第一块积木:Promise

  • async 函数 永远返回一个 Promise
  • await 只能等 Promise 结果
js 复制代码
async function demo() {
  return 123;   // 自动包一层 Promise.resolve(123)
}
demo().then(console.log); // 123

三、第二块积木:Generator 暂停/恢复

Generator 可以"停住函数、记住上下文、外部注入值",是 async/await 的底层发动机。

js 复制代码
function* gen() {
  const a = yield 1; // 停!把 1 交出去,等外部把结果塞回 a
  const b = yield 2 + a;
  return b;
}

const g = gen();
g.next();      // {value: 1, done: false}
g.next(10);    // 把 10 塞回 a,继续到 yield 12,{value: 12}
g.next(100);   // 把 100 塞回 b,{value: 100, done: true}

四、第三块积木:自执行器(co 库 20 行实现)

把 Generator 的 .next() 写成自动循环,就成了 co

js 复制代码
function co(gen) {
  return new Promise((resolve, reject) => {
    const g = gen();
    function step(val) {
      const { value, done } = g.next(val);
      if (done) return resolve(value);
      Promise.resolve(value).then(step, reject);
    }
    step();
  });
}

使用:

js 复制代码
co(function* () {
  const user = yield fetchUser(1);
  const order = yield fetch(`/order/${user.lastOrder}`).then(r => r.json());
  return order;
}).then(console.log);

这就是 Generator + 自执行器 的"伪 async/await"。


五、第四块积木:官方 async/await ------ 语法糖合体

Babel 转译后,你的 async 函数 ≈ 被 co 包装后的 Generator

源码

js 复制代码
async function getDetail(id) {
  const user = await fetchUser(id);
  const order = await fetch(`/order/${user.lastOrder}`).then(r => r.json());
  return order;
}

转译后(简化)

js 复制代码
function getDetail(id) {
  return co(function* () {
    const user = yield fetchUser(id);
    const order = yield fetch(`/order/${user.lastOrder}`).then(r => r.json());
    return order;
  });
}

六、错误处理三板斧

场景 写法
try/catch 捕获 try { await xxx } catch(e) {}
并发错误 Promise.allSettled([...])
超时兜底 await Promise.race([fetch(), sleep(5000)])

七、并发与串行对比代码

js 复制代码
// 串行:2 s + 2 s = 4 s
const a = await delay(2000);
const b = await delay(2000);

// 并发:max(2 s, 2 s) = 2 s
const [a, b] = await Promise.all([delay(2000), delay(2000)]);

八、手写 async/await 面试题

题目:用 Generator 实现 sleep 函数 + async/await 效果。

js 复制代码
function sleep(ms) {
  return new Promise(r => setTimeout(r, ms));
}

function* genSleep() {
  console.time('sleep');
  yield sleep(1000);
  console.timeEnd('sleep'); // ≈ 1000 ms
}

co(genSleep);

九、思维导图总结

javascript 复制代码
async/await
├─ 语法糖
├─ 基于 Promise
├─ 内部使用 Generator + 自执行器
└─ Babel 转译 ≈ co 库

🏁 结语

把 async/await 拆成 4 块乐高后,你会发现:

  • 它并不神秘,只是 Promise + Generator + 自执行器 的优雅封装。
  • 写代码时:串行/并发、错误、超时,套路固定。
  • 面试回答时:先画模型,再给代码,稳拿 Offer!

下次面试官再问 async/await 原理,你可以自信地说:

"先生,我会拼乐高。"

相关推荐
恋猫de小郭5 小时前
Flutter Zero 是什么?它的出现有什么意义?为什么你需要了解下?
android·前端·flutter
崔庆才丨静觅11 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby606112 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了12 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅12 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅13 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅13 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment13 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅13 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端