← 返回目录

15. async / await

async 是在函数门口挂个牌子"本房间办异步业务",await"在这一步停下来,等结果"。两个配合,让异步代码写得像同步代码——不再 .then.then

15.1 互动演示(模拟三顿外卖)

点按钮,看 await 怎么"拦住"代码一步步走。

15.2 知识点讲解

① .then 接结果 → await 等结果

以前 .then 像"留个电话,好了打给我";await 像"站在原地等,好了再走下一步"。

function getData() {              // 一个返回 Promise 的函数
  return new Promise(resolve => {  // 造一个承诺
    setTimeout(() => resolve("数据来了"), 500); // 500 毫秒后兑现
  });
}

// 以前:.then 回调接
getData.then(data => {            // 好了再打给我
  console.log(data);              // 拿到结果
});

// 现在:async 函数里 await 等
async function main() {          // 门口挂牌"办异步业务"
  let data = await getData(); // ★ 在这里停住,等它出结果
  console.log(data);              // 等到了再打印
}
main(); // 调一下

await 会"拦住"代码:上一行等完,才执行下一行。结果直接当普通变量用,不用再写回调函数。

② 失败处理:.catch → try...catch

以前失败走 .catch,现在用同步代码那套 try...catch 接住就行。

// 以前
getData.then(d => console.log(d)) // 成功走 then
  .catch(err => console.log("失败:", err)); // 失败走 catch

// 现在
async function main() {          // async 函数里
  try {                           // 包一层 try
    let data = await getData(); // 失败会像普通异常一样抛出
    console.log(data);            // 成功就打印
  } catch (err) {                 // 失败被 catch 接住
    console.log("失败:", err); // catch 接住
  }
}

await 的 Promise 失败时,会像普通代码一样"抛出异常",try...catch 就能接住,跟同步代码的错误处理完全一致。

③ 多个 await:按顺序一个个等

async function main() {          // async 函数里
  let a = await getData("第一个"); // 等第一个
  let b = await getData("第二个"); // 第一个完了才等第二个
  console.log(a);                 // 打印第一个结果
  console.log(b);                 // 打印第二个结果
}

注意:两个 await 是串行等待(总耗时相加)。如果两个请求互不依赖,应该用 Promise.all([p1, p2]) 并行,总耗时只取最长的——这是性能优化点。

④ 注意:await 只能在 async 里,async 返回值被包成 Promise

// await 离开 async 函数会报错
// await getData;  // ★ 报错(顶层要 ES2022 模块才支持)

// async 函数 return 的值,外面要 then / await 才能拿
async function fn() {           // async 函数
  return 123; // 你以为返回 123,其实返回 Promise<123>
}
fn.then(v => console.log(v)); // 123

如果你写了 const x = asyncFn 然后直接把 x 当数字用,会发现 x 是个 Promise 对象。因为 async 函数的返回值会自动被包成 Promise——外面必须再 await.then 才能拿到真实值。

15.3 实战:用在哪 / 常见坑 / 怎么解决

① 可能在什么地方用:接口请求后再渲染页面、登录后拉用户信息再跳转、按顺序执行的多步异步任务、封装"等结果再继续"的业务逻辑。

② 常见的问题:await 写在普通函数外面报错;async 函数 return 出来的直接当值用(其实是 Promise);多个不相关的 await 串行导致页面慢。

③ 解决思路:await 必须写在 async 函数或模块顶层;async 返回值再 await 一层;无依赖并发用 Promise.all([p1, p2]);失败一律 try...catch 包起来。

一句话:async 声明异步函数,await 在里面等结果,异步代码写得像同步;失败用 try...catch 接。