Async/Await:让异步像同步一样简单

上一期我们学会了用 Promise 链式调用来摆脱回调地狱。

今天我们再往前迈一步,用 async/await 把异步代码写得像同步代码一样直观

async/await 是 ES2017 引入的语法糖,本质上还是 Promise,但极大提升了代码的可读性。

1. 基本写法

javascript 复制代码
// 普通 Promise 写法
function fetchUser() {
  return fetch('/api/user')
    .then(res => res.json())
    .then(data => data.user);
}

// async/await 写法
async function fetchUser() {
  const res = await fetch('/api/user');
  const data = await res.json();
  return data.user;
}

关键点

  • 在函数前加 async,这个函数就自动返回一个 Promise
  • 在 Promise 前面加 await,表示"等到这个 Promise 完成再继续往下走"
  • 代码从上到下顺序执行,像写同步代码一样

2. 错误处理:使用 try...catch

javascript 复制代码
async function loginFlow(username, password) {
  try {
    const token = await login(username, password);
    const user = await getUserInfo(token);
    const products = await getRecommendations(user.level);
    
    renderProducts(products);
    showSuccess("欢迎回来!");
  } catch (error) {
    console.error("登录流程失败:", error);
    showError("出错了,请稍后重试");
  }
}

优点

  • 只需要一个 try...catch,就能捕获整个流程中任意一步的错误
  • 错误位置清晰,栈追踪更有意义
  • 比 Promise 的 .catch() 更接近我们熟悉的同步错误处理方式

3. 常见使用场景

3.1 顺序执行多个异步操作

javascript 复制代码
async function processOrder() {
  const order = await getOrderFromDB(orderId);
  const payment = await processPayment(order.amount);
  const shipping = await createShippingLabel(payment);
  await sendConfirmationEmail(shipping.trackingNumber);
  
  return shipping;
}

3.2 与 Promise.all 结合实现并发

javascript 复制代码
async function loadUserData(userId) {
  const [profile, posts, friends] = await Promise.all([
    fetch(`/api/profile/${userId}`),
    fetch(`/api/posts/${userId}`),
    fetch(`/api/friends/${userId}`)
  ]);
  
  // 三个请求并发发起,最后一起等待完成
  const profileData = await profile.json();
  const postsData = await posts.json();
  const friendsData = await friends.json();
  
  return { profileData, postsData, friendsData };
}

3.3 在循环中使用 await(注意性能)

javascript 复制代码
// 顺序执行(适合需要前一步结果的情况)
async function processItems(items) {
  for (const item of items) {
    const result = await processSingleItem(item);
    saveResult(result);
  }
}

// 如果不需要顺序,可以先 Promise.all 再循环
async function processItemsInParallel(items) {
  const promises = items.map(item => processSingleItem(item));
  const results = await Promise.all(promises);
  results.forEach(saveResult);
}

4. 常见陷阱与注意事项

问题 错误写法 正确写法 说明
在循环里 await 导致串行慢 forEach(item => await fn(item)) for...ofPromise.all forEach 不等待
忘记 await const data = fetch(url) const data = await fetch(url) 否则得到 Promise 对象
try...catch 范围太小 只 catch 单行 包住整个流程 否则错误漏掉
顶层 await 不支持(旧环境) 包在 async 函数里 现代模块支持顶层 await
性能误用 所有操作都 await 能并行的用 Promise.all 避免不必要的等待

5. 真实业务对比

Promise 链式

js 复制代码
login(username, pwd)
  .then(token => getUserInfo(token))
  .then(user => getRecommendations(user.level))
  .then(products => render(products))
  .catch(err => showError(err));

async/await

js 复制代码
async function start() {
  try {
    const token = await login(username, pwd);
    const user = await getUserInfo(token);
    const products = await getRecommendations(user.level);
    render(products);
  } catch (err) {
    showError(err);
  }
}

大多数开发者认为后者更清晰、更容易维护。

6. 小结:async/await 的核心价值

  • 可读性:代码结构接近日常同步思维
  • 错误处理:统一的 try...catch
  • 调试友好:断点更容易命中预期位置
  • 与 Promise 完全兼容:该并发时用 Promise.all,该顺序时用 await

一句话总结

async/await 让异步代码看起来像同步代码,但依然保留了异步非阻塞的本质。

下一期我们将把学到的异步知识应用到实际网络请求中:
Fetch API 与异步网络请求 ------ 现代浏览器中最常用的数据获取方式。

我们下期见~

留言区互动:

你更喜欢 Promise 链式还是 async/await?

有没有在项目中因为 async/await 写法而修复过 bug 的经历?

相关推荐
明月_清风几秒前
自定义右键菜单:在项目里实现“选中文字即刻生成新提示”
前端·javascript
明月_清风1 分钟前
告别后端转换:高质量批量导出实战
前端·javascript
刘发财5 小时前
弃用html2pdf.js,这个html转pdf方案能力是它的几十倍
前端·javascript·github
牛奶7 小时前
2026年大模型怎么选?前端人实用对比
前端·人工智能·ai编程
牛奶7 小时前
前端人为什么要学AI?
前端·人工智能·ai编程
Kagol10 小时前
🎉OpenTiny NEXT-SDK 重磅发布:四步把你的前端应用变成智能应用!
前端·开源·agent
GIS之路11 小时前
ArcGIS Pro 中的 notebook 初识
前端
JavaGuide11 小时前
7 道 RAG 基础概念知识点/面试题总结
前端·后端
ssshooter11 小时前
看完就懂 useSyncExternalStore
前端·javascript·react.js
格砸12 小时前
从入门到辞职|从ChatGPT到OpenClaw,跟上智能时代的进化
前端·人工智能·后端