Async/Await 详解(JavaScript)
async/await 是 ES2017 (ES8) 引入的异步编程语法糖,基于 Promise 实现,让异步代码的书写和阅读更接近同步方式,彻底解决了回调地狱问题。
核心概念
async 函数
- 声明一个异步函数:
async function myFunc() { ... }
- 返回值:总是返回一个 Promise 对象。
- 函数内 return 的值会被包装成
Promise.resolve(value)
- 抛出错误时返回
Promise.reject(error)
1 2 3 4
| async function foo() { return 42; } foo().then(console.log);
|
await 表达式
- 只能在
async 函数内部使用。
await promise:暂停当前 async 函数的执行,等待 Promise 完成。
- 若 Promise 成功(fulfilled),返回 resolve 的值。
- 若 Promise 失败(rejected),抛出错误(可用 try/catch 捕获)。
1 2 3 4 5 6 7
| async function bar() { const result = await new Promise((resolve) => setTimeout(() => resolve("完成!"), 1000) ); console.log(result); } bar();
|
执行流程详解
1 2 3 4 5 6 7 8 9 10
| async function example() { console.log("1: 开始"); const data = await fetchData(); console.log(`3: 获取数据: ${data}`); return "处理完毕"; }
console.log("0: 调用前"); example().then(res => console.log(`4: 结果: ${res}`)); console.log("2: 调用后");
|
输出顺序:
0: 调用前
1: 开始
2: 调用后 // 主线程继续执行
3: 获取数据: ... // 异步恢复执行
4: 结果: 处理完毕
错误处理
使用 try/catch 捕获异常:
1 2 3 4 5 6 7 8 9
| async function fetchWithError() { try { const data = await fetch("https://invalid-url"); console.log(data); } catch (error) { console.error("请求失败:", error); } } fetchWithError();
|
关键优势
- 代码简洁:消除嵌套回调,线性化异步逻辑。
- 错误处理统一:使用
try/catch 替代 .catch()。
- 调试友好:可以在
await 行设置断点调试。
- 条件分支清晰:
if/for 等逻辑可直接使用。
注意事项
顶层 await:
ES2022 支持在模块顶层直接使用 await(仅限 ES Modules):
1 2
| const data = await fetchData();
|
并行优化:
多个独立异步操作应并行执行,避免串行等待:
1 2 3 4 5 6
| const r1 = await task1(); const r2 = await task2();
const [r1, r2] = await Promise.all([task1(), task2()]);
|
循环中的 await:
在循环中需注意执行顺序:
1 2 3 4 5 6 7
| for (const url of urls) { await fetch(url); }
await Promise.all(urls.map(url => fetch(url)));
|
常见问题
Q: await 会阻塞主线程吗?
A: 不会!await 只是暂停当前 async 函数的执行,将控制权交还事件循环,主线程可继续处理其他任务。
Q: 能否在普通函数中用 await?
A: 不能!会抛出语法错误。只能在 async 函数内使用。
Q: async/await 会替代 Promise 吗?
A: 不会!它们是互补的:
async/await 用于控制异步流程
- Promise 仍是异步操作的底层基础
总结
async/await 是 JavaScript 异步编程的革命性改进:
- 用同步写法实现异步逻辑
- 基于 Promise,兼容现有异步库
- 错误处理更符合直觉
- 大幅提升代码可读性和可维护性
最佳实践:所有返回 Promise 的函数都可用 await 调用,配合 try/catch 处理错误,用 Promise.all() 优化并行任务。