JavaScript 是单线程语言,异步编程是它的核心能力。从回调函数到 Promise 再到 async/await,异步写法的演进方向就是让代码越来越接近同步的阅读体验。
1. 回调地狱的问题
// 回调套回调,缩进越来越深,错误处理重复分散
getUser(id, function(err, user) {
if (err) return handleError(err);
getOrders(user, function(err, orders) {
if (err) return handleError(err);
getDetail(orders[0], function(err, detail) {
// ...
});
});
});
2. Promise 基础
Promise 表示一个「未来才会有结果」的值,有 pending、fulfilled、rejected 三种状态,状态一旦改变不可逆:
const p = new Promise((resolve, reject) => {
setTimeout(() => resolve("完成"), 1000);
});
p.then(result => console.log(result)) // 完成时执行
.catch(err => console.error(err)) // 失败时执行
.finally(() => console.log("无论如何都执行"));
链式调用让嵌套变成平铺,前一个 then 的返回值会传给下一个 then:
getUser(id)
.then(user => getOrders(user)) // 返回 Promise,自动等待
.then(orders => getDetail(orders[0]))
.then(detail => console.log(detail))
.catch(handleError); // 任一环节出错都到这里
3. async/await:同步风格的异步
async 函数内部可以用 await 等待 Promise,代码写法上和同步完全一致,用 try/catch 处理错误:
async function loadAll() {
try {
const user = await getUser(id);
const orders = await getOrders(user);
const detail = await getDetail(orders[0]);
return detail;
} catch (err) {
handleError(err);
}
}
注意:await 之外的 async 函数仍是同步执行到第一个 await,await 之后的部分相当于放进了 then。
4. 并行与串行的选择
多个互不依赖的异步任务,串行 await 会白白等待,应该用 Promise.all 并行:
// 串行:总耗时 = 三个请求之和
const a = await fetchA();
const b = await fetchB();
const c = await fetchC();
// 并行:总耗时 ≈ 最慢的那个
const [a, b, c] = await Promise.all([fetchA(), fetchB(), fetchC()]);
// 需要全部结果(允许部分失败)用 allSettled
const results = await Promise.allSettled([fetchA(), fetchB()]);
5. 常见陷阱
两个最常犯的错误:一是在 forEach 里用 await(forEach 不等待异步回调,改用 for…of 逐个 await,或用 map 生成 Promise 数组后 Promise.all);二是循环里的 await 导致意外串行,能并行的一定用 Promise.all。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END








暂无评论内容