Promise与async/await

本专栏聚焦Promise的核心原理与高级应用,包含: ✓ Promise A+规范深度解读 ✓ 手写实现与源码分析 ✓ 异步编程设计模式 ✓ 性能调优与错误处理
适合有JavaScript基础,希望深入异步编程的开发者。我们将用最少的篇幅,讲透最核心的知识。

引言

在之前的文章中,我们学习了Promise的基础和原理实现。从中我们不难发现,即使是链式调用,处理复杂的异步流程仍然有些繁琐,我们来看下面的例子:

javascript 复制代码
// Promise链式调用
fetchUser(userId)
    .then(user => fetchOrders(user.id))
    .then(orders => processOrders(orders))
    .then(result => displayResult(result))
    .catch(error => handleError(error))
    .finally(() => cleanup());

在这种情况下,async/await语法应运而生,它让我们可以用同步的方式写异步代码:

javascript 复制代码
// async/await版本
async function displayUserOrders(userId) {
    try {
        const user = await fetchUser(userId);
        const orders = await fetchOrders(user.id);
        const result = await processOrders(orders);
        displayResult(result);
    } catch (error) {
        handleError(error);
    } finally {
        cleanup();
    }
}

async:声明异步函数

基本语法

async 关键字用于声明一个异步函数:

javascript 复制代码
// async函数声明
async function getUser() {
    return { name: '张三', age: 25 };
}

// async函数表达式
const getData = async function() {
    return '数据';
};

// async箭头函数
const fetchData = async () => {
    return await fetch('/api/data');
};

// async方法
class UserService {
    async getUser(id) {
        // 异步操作
    }
}

函数返回值

async 函数总是返回一个 Promise

javascript 复制代码
async function basicReturn() {
    return 42; // 等价于 Promise.resolve(42)
}

async function promiseReturn() {
    return Promise.resolve('hello'); // 返回的Promise
}

async function throwError() {
    throw new Error('失败'); // 等价于 Promise.reject(error)
}

await:等待Promise解决

基本使用

await 只能在 async 函数内部使用,它会暂停 async 函数的执行,等待Promise解决:

javascript 复制代码
async function example() {
    console.log('开始执行');
    
    // await会暂停执行,直到Promise解决
    const result = await fetchData();
    
    console.log('数据获取完成:', result);
    return result;
}

// 等价于
function examplePromise() {
    console.log('开始执行');
    
    return fetchData().then(result => {
        console.log('数据获取完成:', result);
        return result;
    });
}

错误处理:try-catch的回归

同步风格的错误处理

javascript 复制代码
// 传统Promise错误处理(分散)
fetchUser()
    .then(user => {
        return fetchOrders(user.id)
            .catch(orderError => {
                console.error('获取订单失败:', orderError);
                return [];
            });
    })
    .catch(userError => {
        console.error('获取用户失败:', userError);
    });

// async/await错误处理(集中)
async function getUserOrders() {
    try {
        const user = await fetchUser();
        try {
            const orders = await fetchOrders(user.id);
            return orders;
        } catch (orderError) {
            console.error('获取订单失败:', orderError);
            return []; // 返回默认值
        }
    } catch (userError) {
        console.error('获取用户失败:', userError);
        throw userError; // 重新抛出
    }
}

// 更简洁的版本
async function getUserOrdersBetter() {
    try {
        const user = await fetchUser();
        const orders = await fetchOrders(user.id);
        return orders;
    } catch (error) {
        console.error('操作失败:', error);
        // 根据错误类型处理
        if (error.message.includes('用户')) {
            throw new Error('用户相关操作失败');
        }
        return []; // 默认值
    }
}

多await操作的错误处理

javascript 复制代码
async function multipleOperations() {
    // 方法1:分别处理每个await(粒度细)
    let user;
    try {
        user = await fetchUser();
    } catch (error) {
        console.error('获取用户失败');
        return null;
    }
    
    let orders;
    try {
        orders = await fetchOrders(user.id);
    } catch (error) {
        console.error('获取订单失败,但用户数据有效:', user);
        orders = [];
    }
    
    // 方法2:统一处理(粒度粗)
    try {
        const user = await fetchUser();
        const orders = await fetchOrders(user.id);
        const products = await fetchProducts(orders);
        return { user, orders, products };
    } catch (error) {
        console.error('某个步骤失败:', error);
        // 无法区分哪个步骤失败
    }
    
    // 方法3:组合使用(推荐)
    try {
        const user = await fetchUser().catch(() => {
            throw new Error('用户获取失败,终止流程');
        });
        
        const orders = await fetchOrders(user.id).catch(() => {
            console.warn('订单获取失败,使用空数组');
            return [];
        });
        
        // 即使orders为空,也继续执行
        const analysis = await analyzeData(user, orders);
        return analysis;
    } catch (error) {
        console.error('致命错误:', error);
        return null;
    }
}

停止和恢复执行

async/await 中真正起作用的是 awaitasync 关键字只是一个标识符。我们可以看下面一个例子:

javascript 复制代码
async function test() {
    console.log(await Promise.resolve(1));
}
async function test2() {
    console.log(await '2');
}

async function test3() {
    console.log(3);
}
test();
test2();
test3();

上述代码的输出结果是:3 2 1 。因为JS运行时,在碰到 await 关键字时,会记录在哪里执行暂停。等待 await 后边的值可以用了,JS运行时会向消息队列中推送一个任务,这个任务会恢复函数执行。

结语

Promiseasync/await 是JS异步编程的黄金组合:Promise 提供了底层的异步抽象和组合能力,async/await 提供了上层的语法糖,让异步代码更易读。对于文章中错误的地方或者有任何问题,欢迎在评论区留言讨论!

相关推荐
passerby606131 分钟前
完成前端时间处理的另一块版图
前端·github·web components
掘了38 分钟前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅41 分钟前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅1 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅1 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment2 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅2 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊2 小时前
jwt介绍
前端
爱敲代码的小鱼2 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax
Cobyte2 小时前
AI全栈实战:使用 Python+LangChain+Vue3 构建一个 LLM 聊天应用
前端·后端·aigc