03async 与 await

async/await 是 Promise 的「同步写法」糖: 用 await 等结果,用 try/catch 接错误,代码像同步一样从上往下读。 它不改变异步本质——底层仍是 Promise + 微任务。

约 13 分钟 3 个动手实验 现代异步写法

一、从 then 链到 async 函数

Promise 链横向缩进

load()
  .then(d => parse(d))
  .then(p => save(p))
  .then(() => done())
  .catch(e => fail(e));

async/await纵向阅读

try {
  const d = await load();
  const p = await parse(d);
  await save(p);
  done();
} catch (e) {
  fail(e);
}
两种写法等价。新代码优先 async/await; 并发场景记得 Promise.all,别傻等串行。

二、async 函数的返回值

async 函数永远返回 Promise: 直接 return 的值会被包成 Promise.resolve(值); 抛错则变成 rejected。

async 返回值自动包成 Promise:点按钮看 typeof 与 then 的表现

三、await 在等什么

await 只能写在 async 函数(或模块顶层)里。 它等一个 Promise settle,把 fulfilled 的 value 交出来; 若 rejected,则抛出错误(可用 try/catch 接)。

四、错误处理:try / catch / finally

try/catch 接 await 失败:模拟网络错误,看错误被拦住而不是炸掉整页
忘记 try/catch 的 await 失败会变成 unhandledrejection。在事件回调里调用 async 函数时, 也要保证内部有 catch,或 fn().catch(handle)。

五、串行 vs 并行

连续 await 是串行(等前一个完成才发下一个)。 互不依赖的请求要用 Promise.all 并行,速度差可能是一倍以上。

计时对比:串行 3×200ms vs 并行 ≈200ms
口诀:依赖关系用串行,独立请求用 all。

六、常见模式

模式写法
循环里串行 for (const x of list) await f(x)
循环里并行 await Promise.all(list.map(f))
超时 Promise.race([task(), wait(2000).then(() => { throw … })])
重试 for (…) { try { return await f() } catch { if (last) throw } }
事件回调 btn.addEventListener('click', async () => { try { … } catch {} })

七、async 不是「多线程」

  • await 只是让出主线程,等结果期间别的任务可以跑。
  • 计算密集型任务 await 也救不了——用 Web Worker。
  • async 函数里 await 之后的代码是微任务继续跑的。

八、本章小结

  • async 函数永远返回 Promise;await 等 Promise settle。
  • 错误用 try/catch 接;finally 做清理。
  • 连续 await 是串行;独立请求用 Promise.all 并行。
  • 语法是糖,底层仍是 Promise 微任务——和事件循环知识连起来记。
  • 项目里新写异步逻辑优先 async/await,读起来像同步。
动手练习: ① 把上节课的 Promise 链改写成 async/await; ② 写一个 retry(fn, times) 异步重试工具; ③ 用 Promise.all 并发取 3 个数据,失败的用 allSettled 跳过。