【JavaScript】Promise 与 async/await

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
喜欢就支持一下吧
点赞6 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容