当然,以下是《JavaScript 异步编程 Async/Await 使用详解:从原理到最佳实践》的完整内容,涵盖基础语法、实现原理、异常处理、并发控制、最佳实践、性能建议等方面,并穿插示例与注意事项,适合中高级开发者系统学习。


📘 目录

  1. 什么是异步编程?
  2. Promise 简要回顾
  3. Async/Await 是什么?
  4. Async 函数的工作机制
  5. Await 表达式详解
  6. 异常处理方式
  7. 并发与串行控制技巧
  8. Async/Await 的最佳实践
  9. 常见陷阱与误区
  10. 性能与调试建议
  11. 总结与参考资料

1. 什么是异步编程?

异步编程是处理耗时任务(如网络请求、文件读写、计时器)的主要方式,防止阻塞主线程。

传统方案如:

setTimeout(() => {
  console.log("Hello after 1s");
}, 1000);

回调地狱(callback hell)令人头痛,因此引入了 Promise,再演进为更优雅的 async/await。


2. Promise 简要回顾

function fetchData() {
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve("data loaded"), 1000);
  });
}

fetchData().then(data => console.log(data)).catch(err => console.error(err));

但 .then().then().catch() 可读性差,异常处理复杂。


3. Async/Await 是什么?

Async/Await 是基于 Promise 的语法糖,使异步代码像同步那样书写。

示例

async function load() {
  const data = await fetchData();
  console.log(data);
}
  • async 函数始终返回一个 Promise
  • await 表达式暂停函数执行,等待 Promise 结果

4. Async 函数的工作机制

async function foo() {
  return 42;
}

foo().then(console.log); // 输出 42

本质上等价于:

function foo() {
  return Promise.resolve(42);
}

即使返回普通值也会自动包装为 Promise


5. Await 表达式详解

✅ 正确使用

const response = await fetch(url);
const data = await response.json();

🚫 错误用法:顶级不能直接 await(ES2022 顶级 await 支持后例外)

const result = await someAsyncFunc(); // ⛔ 报错

应包在 async 函数中:

(async () => {
  const result = await someAsyncFunc();
})();

6. 异常处理方式

Async/Await 异常处理推荐使用 try...catch

async function loadData() {
  try {
    const res = await fetch("https://api.example.com/data");
    const json = await res.json();
    console.log(json);
  } catch (err) {
    console.error("请求失败:", err);
  }
}

你也可以使用 .catch()

loadData().catch(console.error);

7. 并发与串行控制技巧

❌ 串行(性能差)

const a = await fetch(url1);
const b = await fetch(url2); // 等待 a 结束后才执行

✅ 并发执行(推荐)

const [a, b] = await Promise.all([fetch(url1), fetch(url2)]);

处理失败也要继续执行

const results = await Promise.allSettled([fetchA(), fetchB()]);

8. Async/Await 的最佳实践

✅ 封装异步逻辑

async function getUser() {
  const res = await fetch("/api/user");
  return await res.json();
}

✅ 显式处理错误

try {
  const data = await getData();
} catch (e) {
  logger.error(e);
}

✅ 使用 loading 状态

async function load() {
  loading = true;
  try {
    const res = await fetchData();
    data = res;
  } finally {
    loading = false;
  }
}

9. 常见陷阱与误区

❌ await forEach 无效!

[1, 2, 3].forEach(async n => {
  await delay(n * 1000);
  console.log(n);
});

这是错误的,因为 forEach 不等待异步。

✅ 使用 for...of

for (const n of [1, 2, 3]) {
  await delay(n * 1000);
  console.log(n);
}

10. 性能与调试建议

✅ 并发处理优化

  • 多请求用 Promise.all 或 Promise.allSettled
  • 不相关任务并行执行,避免 await 阻塞

✅ 异步调试建议

  • 使用 --inspect 启动 Node.js 或 Chrome DevTools
  • 加 debugger 可断点 async 函数
  • 捕捉全局未处理异常:
window.addEventListener("unhandledrejection", e => {
  console.error("未处理的 Promise 错误:", e.reason);
});

11. 总结与参考资料

✅ Async/Await 优势

  • 异步流程同步写法
  • 更清晰的异常处理
  • 可读性强,可维护性高

⚠️ 注意

  • 仅能用于异步函数内
  • 使用 forEach 或 map 配合 await 时要小心
  • 注意性能陷阱,适当并发处理

📚 参考资料