从Promise到async/await的逻辑演进

前言

本文将从Promise详细地循序渐进式地去介绍async和await。

原始异步

我们学习JavaScript过程中时常会遇见以下这样个回调函数,这是我们学习过的最早最原始的异步写法。

js 复制代码
console.log('开始')

setTimeout(function (){
    console.log("1秒后输出")
},1000)

console.log('结束')

上面的代码执行顺序是:'开始'->'结束'->'3秒后执行'。虽然代码简单直观,但不适合处理复杂的异步流程,而且当需要多个异步操作按顺序执行时,会出现一个缺点,缺点就是如果当多层嵌套的时候就会形成"回调地狱",让代码变得可读性差和难以维护以及理解。

回调地狱:

js 复制代码
setTimeout(() => {
    console.log('第一步');
    setTimeout(() => {
        console.log('第二步');
        setTimeout(() => {
            console.log('第三步');
        }, 1000);
    }, 1000);
}, 1000);

所以我们引出了Promise来解决对异步操作的封装,让异步流程能够链式调用,让改善代码这种情况并且更加清晰。

Promise

Promise对象是表示异步操作最终完成(或失败)以及其结果值,是对异步操作的封装,能让异步的流程可以链式调用,代码更清晰。

js 复制代码
function waitOneSecond() {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve('1秒后输出')
        }, 1000)
    })
}

waitOneSecond()  
    .then(result => {
        console.log(result)
})

waitOneSecond函数封装了异步操作,其值是一个Promise对象,表示异步操作的结果和值。

Promise的链式调用

Promise能让异步的流程可以链式调用。如下多个异步操作顺序执行:

js 复制代码
waitOneSecond()
    .then(result => {
        console.log(result)
        return waitOneSecond()
    })
    .then(result => {
        console.log('又过了一秒')
    })
    .catch(error => {
        console.error('出错了', error)
    })

上面的多个异步操作形成了下面的链式形状,虽然比回调要好,但是链式写法多了还是不够直观。

js 复制代码
waitOneSecond() .then() .then() .catch()

为了逻辑更加清晰,我们引出了async/await

async/await

async/await是Promise的语法糖,本质还是基于promise,但其写法更像是同步代码,表达的逻辑也更加清晰。

我们引用MDN中的描述:async function 声明创建一个绑定到给定名称的新异步函数。函数体内允许使用 await 关键字,这使得我们可以更简洁地编写基于 Promise 的异步代码,并且避免了显式地配置 Promise 链的需要。

js 复制代码
async function getUserInfoAsync(userId) {
    try {
        // 串行执行:每个操作都要等待前一个完成
        const user = await fetchUserData(userId);      // 等待1秒
        const orders = await fetchUserOrders(user.id); // 再等待1.5秒
        const total = await calculateTotal(orders);    // 再等待0.5秒
        // 总共需要3秒
        return { user, orders, total };
    } catch (error) {
        console.error('处理过程中出错:', error);
        throw error;
    }
}

上述代码借助async/await,我们使用await等待Promise完成,让代码看起来更像是同步代码(实际依然是异步执行),首先,上述代码使用的是串行处理 (一个接一个),其次是async/await也支持并行处理(同时进行)能力:

js 复制代码
async function getMultipleUsersInfo(userIds) {
    try {
        // 并行执行:同时发起所有请求
        const userPromises = userIds.map(id => getUserInfoAsync(id));
        // Promise.all 等待所有请求完成
        const results = await Promise.all(userPromises);
        return results;
    } catch (error) {
        console.error('获取多个用户信息时出错:', error);
        throw error;
    }
}
相关推荐
LucianaiB4 分钟前
耗时30天,DocPilot Qwen正式开源:一个免费无广的开源文档 AI 助手
前端·后端
xiaoshuaishuai822 分钟前
C# AvaloniaUI 资源找不到报错
java·服务器·前端·windows·c#
丷丩31 分钟前
MapLibre GL JS第35课:显示带地形高程(三维地形)的卫星影像
javascript·gis·map·mapbox·maplibre gl js
How_doyou_do32 分钟前
26字节工程营-前端-自我总结
前端
三乐22834 分钟前
node不认识类型?多半是没用上这几段代码
javascript
十有八七34 分钟前
🧩 组件库死亡倒计时?—— AI 编码冲击下的前端基础设施重构
前端·人工智能
风止何安啊42 分钟前
我一个前端仔,居然用 Python 搞起了 AI?从零到一,撸了个 AI 聊天框小 demo
前端·人工智能·后端
GISer_Jing1 小时前
Claude Code插件系统全解析
前端·人工智能·ai·架构
小茴香3531 小时前
Vue3路由权限动态管理
前端·前端框架·vue3
RANxy1 小时前
零基础全栈 React 入门(四):React Router 路由配置
前端·react.js