解析 JavaScript 异步编程:从回调地狱到 Promise 和 Async/Await

在这里插入图片描述

在现代的JavaScript开发中,处理异步任务变得愈发重要,因为它们允许我们在等待I/O、网络请求或定时器等事件时继续执行其他任务,以提高程序的性能和响应能力。本文将介绍JavaScript中异步编程的演变过程,从最初的回调地狱到后来的Promise和Async/Await。

回调地狱

回调地狱是一种异步编程的反模式,它在嵌套的回调函数中处理多个异步任务,导致代码难以阅读和维护。以下是一个简单的回调地狱演示:

function add(a: number, b: number, callback: (res: number) => void): void  {setTimeout(() => {callback(a + b);}, 1000);
}// 回调地狱示例
add(2, 3, res => {console.log('2 + 3 = ', res);add(res, 4, res => {console.log('2 + 3 + 4 = ', res);add(res, 5, res => {console.log('2 + 3 + 4 + 5 = ', res);});});
});

如上所示,每个异步任务的结果都在回调函数中处理,形成了嵌套的结构,使得代码难以理解。

Promise

Promise是一种用于处理异步任务的对象,它代表了一个异步操作的最终完成或失败,并提供了更优雅的解决方案,避免了回调地狱的问题。

async function add2(a: number, b: number): Promise<number>  {return new Promise((resolve, reject) => {setTimeout(() => {resolve(a + b);}, 2000);});
}// Promise链式调用
add2(2, 3).then((res: number )=> {console.log('2 + 3 = ', res);return add2(res, 4);}).then((res: number )=>{console.log('2 + 3 + 4 = ', res);return add2(res, 4);}).then((res: number) => {console.log('result:', res);}).catch(e => console.error(`ERROR: ${e}`));

通过Promise,我们可以将异步任务按顺序组织在链式调用中,使得代码更具可读性。

Promise的异常捕获

Promise还提供了异常捕获机制,使得我们可以方便地处理异步任务的错误。

add2(2, 3).then((x: number )=> Promise.reject(10)).then((x: number )=> add2(x, 6)).then((res: number) => console.log(res)).catch(e => console.error(`ERROR: ${e}`));

在这个例子中,当第一个Promise返回了一个拒绝状态时,异常会被捕获,而不会继续执行后续的Promise。

Promise的组合

Promise.all和Promise.race是Promise的两个重要方法。Promise.all等待所有Promise都完成,而Promise.race在第一个Promise完成时就终止。

// Promise同时等待后做事情
Promise.all([add2(2, 3), add2(4, 5)]).then(([a , b]) => {console.log('result', a, b);return mul(a, b);
}).then((res: number) =>console.log('result:', res)
);// Promise谁先做事情就用谁
Promise.race([add2(2, 3), mul(4, 5)]).then((res: number) =>console.log('result:', res)
);

这两个方法使我们能够更灵活地组合和控制多个异步任务的执行。

Async/Await

Async/Await是ES2017引入的异步编程语法糖,使得异步代码更加像同步代码一样,进一步提高了可读性。

async function main(): Promise<void> {try {const result1 = await add2(2, 3);console.log('2 + 3 = ', result1);const result2 = await add2(result1, 4);console.log('2 + 3 + 4 = ', result2);const result3 = await add2(result2, 5);console.log('2 + 3 + 4 + 5 = ', result3);} catch (error) {console.error(`ERROR: ${error}`);}
}main();

使用Async/Await,我们可以更清晰地表达异步任务的执行顺序,避免了回调地狱和过多的Promise链。

总的来说,JavaScript异步编程的演进经历了从回调地狱到Promise和最终的Async/Await的过程,这些新的语法和模式为开发者提供了更强大和清晰的工具,使得异步代码更易于编写和维护。希望本文对你理解JavaScript异步编程有所帮助。

JavaScript异步编程的最新进展:从Promise.allSettled到Promise.any

在ES2020和ES2021中,JavaScript引入了一些新的异步编程方法,进一步改善了处理Promise的体验。本文将介绍其中两个方法:Promise.allSettledPromise.any

Promise.allSettled(ES2020)

在ES2020中,JavaScript引入了 Promise.allSettled 方法,它用于处理多个Promise,无论它们是被解决(fulfilled)还是被拒绝(rejected)。

function asyncFunction1(): Promise<string> {return new Promise(resolve => setTimeout(() => resolve('Result from asyncFunction1'), 1000));
}function asyncFunction2(): Promise<number> {return new Promise(resolve => setTimeout(() => resolve(42), 500));
}// 使用 allSettled 扩展方法
const promises = [asyncFunction1(), asyncFunction2()];Promise.allSettled(promises).then(results => {results.forEach(result => {if (result.status === 'fulfilled') {console.log(`Fulfilled: ${result.value}`);} else {console.log(`Rejected: ${result.reason}`);}});
});

Promise.allSettled 返回一个新的Promise,该Promise在所有传入的Promise都已经被解决或被拒绝后才被解决。它返回一个包含每个Promise结果的对象数组,每个对象都包含 statusvaluereason 属性。

这使得我们能够轻松地处理多个Promise的状态,而不必担心其中一个Promise被拒绝而导致整个操作失败。

Promise.any(ES2021)

在ES2021中,JavaScript引入了 Promise.any 方法,它用于处理多个Promise,只要其中至少有一个被解决。

function asyncFunction3(): Promise<string> {return new Promise(resolve => setTimeout(() => resolve('Result from asyncFunction3'), 1000));
}function asyncFunction4(): Promise<number> {return new Promise((_, reject) => setTimeout(() => reject('Error from asyncFunction4'), 500));
}// 使用 any 扩展方法
const promises2 = [asyncFunction3(), asyncFunction4()];Promise.any(promises2).then(result => {console.log(`Resolved: ${result}`);// 处理至少一个 Promise 被 resolved 的逻辑}).catch(errors => {console.error(`Rejected with all errors: ${errors}`);// 处理所有 Promise 都被 rejected 的逻辑});

Promise.any 返回一个新的Promise,该Promise在传入的Promise中至少有一个被解决后就被解决。它只要有一个Promise被解决,就会返回该Promise的解决值。

这个方法很有用,因为它提供了一种在多个异步任务中找到第一个成功解决的任务的方式。

这两个新方法为JavaScript开发者提供了更多处理异步任务的选择,使得我们能够更灵活地应对各种异步场景。希望这篇文章对你理解Promise.allSettledPromise.any有所帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/669425.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

容器和镜像

容器和镜像是现代软件开发和部署中重要的概念&#xff0c;它们通常与容器化技术&#xff08;如Docker&#xff09;相关联。以下是它们的基本定义和关系&#xff1a; 容器(Container): 容器是一种轻量级、可移植的运行环境&#xff0c;其中包含了应用程序及其依赖项&#xff08;…

简单实践 spring clound 使用openfeign

1.概要 这是在前面工程基础上的一个变更。 前工程&#xff1a;检查实验 spring cloud nacos nacos-server-2.3.0-CSDN博客 2 代码 2.1 引入依赖 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-open…

您企业的(AI)人工智能处于哪个准备阶段?

全新AI准备度评估工具现已推出 根据Gartner 2020年CIO调查报告&#xff0c;仅19%的首席信息官声称其AI项目已投产。这意味着&#xff0c;如果要将AI计划部署到生产过程中&#xff0c;高达80%的企业无法实现。我们发现&#xff0c;澳鹏客户取得成功的几率要高出三倍&#xff0c…

C++类与对象(下)

前言&#xff1a;哈喽小伙伴们&#xff0c;这篇文章我们将继续分享类与对象的剩余知识。 目录 一.const修饰成员函数 二.再谈构造函数 三.友元 1.友元函数 2.友元类 总结 一.const修饰成员函数 我们都知道const是一个将变量定义为静态的关键字&#xff0c;使其不能被修改…

C语言之自定义类型:结构体

目录 1. 结构体类型的声明结构体回顾结构的声明 2. 结构体变量的创建和初始化结构体的特殊声明结构体的自引用 3. 结构体内存对齐对齐规则对齐规则练习1对齐规则练习2对齐规则练习3对齐规则练习4 为什么存在内存对齐offsetof - 计算结构体成员相较于起始位置的偏移量修改默认对…

协同办公的2024开年大战,打的就是“超级助理”

文|智能相对论 作者|沈浪 开年&#xff0c;腾讯发布了一份报告《影响2024年的十大科技应用趋势》。其中提到&#xff0c;从大脑到Agent&#xff0c;大模型从CoPilot副驾&#xff0c;走向主驾驶。在不久的将来&#xff0c;任何上网的人都将能够拥有由人工智能驱动的个人助手&a…

Java学习-内部类

内部类概述 1.成员内部类 注意&#xff1a; 2.静态内部类 3.局部内部类&#xff08;看看就行&#xff09; 4.匿名内部类 应用场景&#xff1a;通常作为一个参数传给方法 Eg.小猫和小狗都参加游泳比赛

【算法】{画决策树 + dfs + 递归 + 回溯 + 剪枝} 解决排列、子集问题(C++)

文章目录 1. 前言2. 算法例题 理解思路、代码46.全排列78.子集 3. 算法题练习1863.找出所有子集的异或总和再求和47.全排列II17.电话号码的字母组合 1. 前言 dfs问题 我们已经学过&#xff0c;对于排列、子集类的问题&#xff0c;一般可以想到暴力枚举&#xff0c;但此类问题用…

单片机的50个电路

单片机 电源 声音模块 收音机 485 蓝牙 光耦 can 光敏电阻 单片机 矩阵 单片机电路 时钟 ADC 接口电路 红外发射 显示模块 红外接收 蜂鸣器驱动 流水灯 usb供电 烧录电路 数码管 EEPROM LCD1602电路 数码管 max485 红外开关 译码器 移位寄存器 步进电机控制 复位电路 下载电路 …

基于springboot智慧养老平台源码和论文

首先,论文一开始便是清楚的论述了系统的研究内容。其次,剖析系统需求分析,弄明白“做什么”,分析包括业务分析和业务流程的分析以及用例分析,更进一步明确系统的需求。然后在明白了系统的需求基础上需要进一步地设计系统,主要包罗软件架构模式、整体功能模块、数据库设计。本项…

挑战!贪吃蛇小游戏的实现(1)

引言 相信大家都玩过贪吃蛇这个游戏&#xff01; 玩家控制一个不断移动的蛇形角色&#xff0c;在一个封闭空间内移动。随着时间推进&#xff0c;这个蛇形角色会逐渐增长&#xff0c;通常是通过吞食屏幕上出现的物品&#xff08;如点或者其他标志&#xff09;来实现。每当贪吃…

《低功耗方法学》翻译——附录B:UPF命令语法

附录B&#xff1a;UPF命令语法 本章介绍了文本中引用的所选UPF命令的语法。 节选自“统一电源格式&#xff08;UPF&#xff09;标准&#xff0c;1.0版”&#xff0c;经该Accellera许可复制。版权所有&#xff1a;(c)2006-2007。Accellera不声明或代表摘录材料的准确性或内容&…

monaco-editor布局篇(二)-自动换行

monaco-editor的换行方式&#xff0c;主要分为3种情况&#xff1a; 不换行按照编辑器宽度换行按照制定列数换行 主要受wordwrap和wordwrapcolumn控制&#xff0c;具体如下&#xff1a; 取值含义off不换行&#xff0c;会一直滚动on换行&#xff0c;文本将在视区宽度内自动换行…

Linux命令:traceroute命令

目录 traceroute1、简介2、探测原理3、traceroute说明4、实例设置每跳探测数设置跳数探测包使用的基本UDP端口设置6789把对外发探测包的等待响应时间设置为3秒 总结 traceroute 1、简介 traceroute的主要功能是跟踪从IP网络发送到指定主机经过的网关的工具。它利用IP协议的生…

5 分钟让你了解什么是搜索引擎

文章目录 搜索引擎概述基于业务模式分类垂直搜索&#xff08;垂搜&#xff09;通用搜索&#xff08;通搜&#xff09;本地搜索引擎 基于技术实现分类基于关键词的搜索引擎&#xff08;Keyword-based Search Engine&#xff09;语义搜索引擎&#xff08;Semantic Search Engine&…

幻兽帕鲁mac可以玩吗?

《幻兽帕鲁》&#xff08;英文&#xff1a;Palworld&#xff09;是一款近期在 Steam 爆红的动作冒险生存游戏&#xff0c;游戏设置在一个居住着「帕鲁」的开放世界中&#xff0c;玩家可以战斗并捕捉帕鲁&#xff0c;也能用它们来建造基地、骑乘和战斗。 不过目前《幻兽帕鲁》仅…

C语言内存函数:memcpy、memcat、memmove介绍和模拟实现(实用性高,建议三连收藏)

目录 1.memcpy函数 1.1函数介绍 1.2函数示范使用 1.3函数的模拟实现 1.4补充 2.memmove函数 2.1函数介绍 2.2函数的使用示范 2.3函数的模拟实现 3.memcmp(内存比较函数&#xff09; 3.1函数介绍 3.2函数的示范使用&#xff0c;有趣的例子 4.函数补充memset(内存…

【靶场实战】Pikachu靶场RCE漏洞关卡详解

Nx01 系统介绍 Pikachu是一个带有漏洞的Web应用系统&#xff0c;在这里包含了常见的web安全漏洞。 如果你是一个Web渗透测试学习人员且正发愁没有合适的靶场进行练习&#xff0c;那么Pikachu可能正合你意。 Nx02 RCE漏洞概述 RCE漏洞&#xff0c;可以让攻击者直接向后台…

【Jenkins】配置及使用|参数化|邮件|源码|报表|乱码

目录 一、Jenkins 二、Jenkins环境搭建 1、下载所需的软件包 2、部署步骤 3、其他 三、Jenkins全局设置 &#xff08;一&#xff09;Manage Jenkins——Tools系统管理->全局工具配置分别配置JDK、Maven、Allure、Git&#xff0c;可以配置路径或者直接选择版本安装 1…

解决zabbix图像中文乱码

使用zabbix查看监控图像信息&#xff0c;发现会有中文乱码现象。 解决方法如下&#xff1a; 1.拷贝windows文字文件到服务器上 C:\Windows\Fonts目录下拷贝自己需要的中文语言文件 2.修改配置文件 vim /usr/share/zabbix/include/defines.inc.php 81行 define(ZBX_GRAPH_F…