Async/Await 详解(JavaScript)
async/await 是 ES2017 (ES8) 引入的异步编程语法糖,基于 Promise 实现,让异步代码的书写和阅读更接近同步方式,彻底解决了回调地狱问题。
核心概念
async函数- 声明一个异步函数:
async function myFunc() { ... } - 返回值:总是返回一个 Promise 对象。
- 函数内 return 的值会被包装成
Promise.resolve(value) - 抛出错误时返回
Promise.reject(error)
- 函数内 return 的值会被包装成
1
2
3
4async function foo() {
return 42; // 等价于 Promise.resolve(42)
}
foo().then(console.log); // 输出 42- 声明一个异步函数:
await表达式- 只能在
async函数内部使用。 await promise:暂停当前async函数的执行,等待 Promise 完成。- 若 Promise 成功(fulfilled),返回 resolve 的值。
- 若 Promise 失败(rejected),抛出错误(可用 try/catch 捕获)。
1
2
3
4
5
6
7async function bar() {
const result = await new Promise((resolve) =>
setTimeout(() => resolve("完成!"), 1000)
);
console.log(result); // 1秒后输出 "完成!"
}
bar();- 只能在
执行流程详解
1 | async function example() { |
输出顺序:
0: 调用前
1: 开始
2: 调用后 // 主线程继续执行
3: 获取数据: ... // 异步恢复执行
4: 结果: 处理完毕
错误处理
使用 try/catch 捕获异常:
1 | async function fetchWithError() { |
关键优势
- 代码简洁:消除嵌套回调,线性化异步逻辑。
- 错误处理统一:使用
try/catch替代.catch()。 - 调试友好:可以在
await行设置断点调试。 - 条件分支清晰:
if/for等逻辑可直接使用。
注意事项
顶层 await:
ES2022 支持在模块顶层直接使用await(仅限 ES Modules):1
2// 模块中
const data = await fetchData(); // 合法并行优化:
多个独立异步操作应并行执行,避免串行等待:1
2
3
4
5
6// 错误(串行): 耗时 time1 + time2
const r1 = await task1();
const r2 = await task2();
// 正确(并行): 耗时 max(time1, time2)
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() 优化并行任务。