← 返回目录

8. async / await

async/await 是 ES2017 的新语法,它是 Promise 的"语法糖"——说白了就是让异步代码写起来像同步代码一样。你不用写 .then.catch 那一串了,直接一行一行从上往下写,看起来就是普通的同步代码,但背后其实是异步在跑。这是现在项目里最主流的写法。

打个比方:以前用 .then 链,像接力赛,一棒接一棒;现在用 await,像你自己一步一步走,走到一个路口等一下,等人来了继续走——读起来就像你平时说话写作文一样自然。

8.1 互动演示(await 串行等待)

点按钮,看 await 怎么让异步代码按顺序走。

8.2 知识点讲解

① 四条核心规则(背下来不犯错)

async/await 用起来很简单,但有四条铁律必须记住:

// 规则1:async 必须写在函数前面
//    只有 async 函数里面才能写 await!
async function getData() {
  // 这里面才能用 await
}

// 规则2:await 后面必须跟一个 Promise 对象
//    await getUser → getUser 返回一个 Promise ✅
//    await 123 → 后面不是 Promise ❌(没意义)

// 规则3:await 会"暂停"当前函数,等 Promise 出结果了再往下走
//    注意:只暂停当前这个函数!不会卡住整个页面!
//    页面照样能点、能滚、能输入

// 规则4:await 的失败不会自动捕获!必须用 try/catch 包起来
//    不然失败了程序直接崩,没人管

如果你在普通函数里写了 await——会直接语法报错——因为 await 只能在 async 函数内部用。如果你忘了 try/catch,接口失败时整个函数静默崩溃,页面啥反应没有——因为 await 的失败会像普通报错一样抛出来,没人接就飞了。

② 标准模板(照着抄就行)

// 标准模板:async 函数 + try/catch + 一行一个 await
async function loadData() {
  try {
    // 第一行:等用户接口完成
    // await 会暂停在这里,等 getUser 返回了再往下走
    let user = await getUser;

    // 第二行:拿到 user.id 了,再查订单
    // 上一行等完了才执行这一行
    let order = await getOrder(user.id);

    // 第三行:两个数据都拿到了
    console.log(user, order);

  } catch (err) {
    // 上面任何一行 await 失败,都会跑到这里来
    console.log("接口出错了:", err);
  }
}

// 最后调用这个函数
loadData(); // 调用函数必须加括号

顺序有依赖的接口,一行一个 await,从上到下写,比 .then 链直白多了——读的时候就像在读普通的同步代码,完全不用想异步的事。

③ 对比:then 链 vs async/await

同样的逻辑,两种写法放一起对比:

// ===== 写法一:then 链(上节课学的) =====
getUser
  .then(function (user) {
    return getOrder(user.id); // 要 return 才传给下一个
  })
  .then(function (order) {
    console.log(order);
  })
  .catch(function (err) {
    console.log(err);
  });

// ===== 写法二:async/await(本课学的,更像同步代码) =====
async function main() {
  try {
    let user = await getUser; // 等完了再下一行
    let order = await getOrder(user.id);
    console.log(order);
  } catch (err) {
    console.log(err);
  }
}
main(); // 调用函数必须加括号

// 两种写法效果完全一样!但 await 读起来自然多了

await 只能在 async 函数里用——如果你在普通的 <script> 顶层直接写 await,会报错,因为顶层不是 async 函数。要么包一个 async 函数,要么用 <script type="module"> 模块模式。

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

可能在什么地方用:

① 项目里调接口的主流写法——所有页面的接口调用都用 async/await;② 有顺序依赖的多个接口(登录→查订单→查详情);③ 配合上节课封装的 request 函数使用。

常见的问题:

① 普通函数里写了 await——语法报错;② 忘了 try/catch,接口失败时静默崩溃;③ 以为 await 卡住了整个页面——其实只卡当前函数;④ 忘了在 async 函数前面加 async 关键字。

解决思路:

① 模板背熟:async function + try { await } catch 三件套;② 每行 await 都假设它可能失败,必须有 catch 兜底;③ 不确定时,把代码复制到 Console 跑一下,报错信息会告诉你哪行出了问题。

一句话:async 声明异步函数,await 等 Promise 结果;顺序依赖一行一个 await,从上到下读;失败用 try/catch 接;await 只暂停当前函数,不卡页面。

8.3 课后作业(融入本节)

练习四:async/await 实战——把上节课用 then 链写的请求调用,改写成 async/await 版本,用 try/catch 捕获错误。要求:① 先 await 拿到用户;② 再 await 用用户 id 查订单;③ 任何一步失败都能在 catch 里看到错误。