异步编程工具Promise与Async/Await:解决前端开发中的嵌套回调地狱

文章目录

    • Promise:处理异步操作的基本工具
      • Promise.all
    • async/await:更简洁的异步编程方式
    • Promise与async/await的比较
    • 结论

当谈及JavaScript中的异步编程时,两个非常常见且强大的工具是Promise和async/await。在本文中,我们将以实际例子中来讨论这两个概念,并探索它们在前端开发中的应用。

先看下面这个例子,还不会使用Promise和async/await之前我就是写下面这样的代码的~

// 使用回调函数来获取一个用户的信息和他的好友列表
function getUser(id, callback) {// 模拟一个异步的请求setTimeout(() => {// 假设id为1的用户存在,其他的用户不存在if (id === 1) {callback(null, { id: 1, name: "Alice" });} else {callback(new Error("User not found"));}}, 1000);
}function getFriends(user, callback) {// 模拟一个异步的请求setTimeout(() => {// 假设用户Alice有两个好友,其他的用户没有好友if (user.name === "Alice") {callback(null, [{ id: 2, name: "Bob" }, { id: 3, name: "Charlie" }]);} else {callback(null, []);}}, 1000);
}

使用嵌套的回调函数来处理结果

// 使用嵌套的回调函数来处理结果
getUser(1, (error, user) => {if (error) {console.error("Error:", error);} else {console.log("User:", user);getFriends(user, (error, friends) => {if (error) {console.error("Error:", error);} else {console.log("Friends:", friends);}});}
});

可以看到上面这个就是一个经典的回调地狱,它(callback hell)是指在JavaScript中使用嵌套的回调函数来处理异步操作的一种编程风格,这种编程风格会导致代码层级过深,难以理解和维护,也不利于错误处理和异常捕获。这就是回调地狱的问题。为了解决这个问题,我们可以使用Promise或async/await等方法来改进代码,让异步操作更加优雅和简洁。

在这里插入图片描述

Promise:处理异步操作的基本工具

Promise是一种用于处理异步操作的对象。它代表了一个可能尚未完成的操作,并可以在操作完成或失败后采取相应的行动。Promise对象有三种状态:待定(pending)、已完成(fulfilled)和已拒绝(rejected)。

在使用Promise时,我们可以使用new Promise()构造函数来创建一个Promise对象。构造函数接受一个执行器函数作为参数,该函数包含两个参数:resolve和reject。通过调用resolve函数,我们可以将Promise从待定状态转换为已完成状态,并传递一个结果值;而通过调用reject函数,我们可以将Promise从待定状态转换为已拒绝状态,并传递一个错误原因。

Promise提供了一组方法,使我们能够在Promise对象上执行各种操作。其中一些方法包括:

  • .then(): 当Promise对象状态为已完成时,可以使用该方法指定一个回调函数来处理结果。
  • .catch(): 当Promise对象状态为已拒绝时,可以使用该方法指定一个回调函数来处理错误。
  • .finally(): 该方法在Promise对象无论状态如何都会执行,无论是已完成还是已拒绝。

使用Promise进行异步编程时,可以将多个Promise对象链接在一起,形成一个Promise链。这样可以按顺序执行异步操作,并在每个操作完成后传递结果到下一个操作。

接下来我们将上述代码使用Promise进行改写

getUser(1).then((user) => {console.log("User:", user);return getFriends(user);}).then((friends) => {console.log("Friends:", friends);}).catch((error) => {console.error("Error:", error);});

尽管Promise是一种强大的工具,但它的语法相对较为冗长,尤其是在处理多个异步操作时。为了解决这个问题,ES2017引入了async/await。

Promise.all

Promise.all是一个静态方法,它可以接收一个Promise对象的数组作为参数,返回一个新的Promise对象,该对象的状态和结果取决于数组中的所有Promise对象的状态和结果。

如果数组中的所有Promise对象都变为fulfilled(已成功)状态,那么Promise.all返回的Promise对象也会变为fulfilled状态,其结果是一个数组,包含了数组中的所有Promise对象的结果。

如果数组中有任何一个Promise对象变为rejected(已失败)状态,那么Promise.all返回的Promise对象也会变为rejected状态,其结果是第一个变为rejected状态的Promise对象的结果。Promise.all可以用来处理多个异步操作的结果,比如并行发送多个网络请求,等待多个定时器完成,等等。

// 使用Promise.all来并行发送三个网络请求,获取三个用户的信息
function getUser(id) {return new Promise((resolve, reject) => {// 模拟一个异步的请求setTimeout(() => {// 假设id为1,2,3的用户存在,其他的用户不存在if (id === 1 || id === 2 || id === 3) {resolve({ id: id, name: `User${id}` });} else {reject(new Error("User not found"));}}, 1000 * id); // 模拟不同的响应时间});
}// 使用Promise.all来处理三个用户的结果
Promise.all([getUser(1), getUser(2), getUser(3)]).then((users) => {console.log("Users:", users);}).catch((error) => {console.error("Error:", error);});

输出结果:

Users: [ { id: 1, name: 'User1' }, { id: 2, name: 'User2' }, { id: 3, name: 'User3' } ]

可以看到,Promise.all返回的Promise对象在三个网络请求都成功后变为fulfilled状态,其结果是一个包含三个用户信息的数组。如果其中有任何一个网络请求失败,那么Promise.all返回的Promise对象就会变为rejected状态,其结果是第一个失败的网络请求的错误。这样,我们就可以使用Promise.all来并行处理多个异步操作的结果,提高代码的效率和可读性。

async/await:更简洁的异步编程方式

async/await是建立在Promise之上的一种语法糖,旨在简化异步代码的编写和阅读。它允许我们以一种看起来同步的方式编写异步代码。

在使用async/await时,我们使用async关键字来定义一个异步函数,该函数可以包含一个或多个await表达式。在异步函数内部,我们可以使用await关键字来等待一个Promise对象的解析,并将其结果赋值给一个变量。在等待期间,函数的执行将暂停,直到Promise解析完成。

同样我们将上述代码使用Promise进行改写

// 使用async/await来处理结果
async function main() {try {let user = await getUser(1);console.log("User:", user);let friends = await getFriends(user);console.log("Friends:", friends);} catch (error) {console.error("Error:", error);}
}main();

Promise与async/await的比较

Promise和async/await都是处理异步操作的强大工具,但它们在语法上有一些区别,因此适用于不同的场景。

Promise适用于以下情况:

  1. 处理较简单的异步操作,不需要嵌套太多层级。
  2. 在需要精细控制异步流程的情况下,使用Promise链可以更直观地表达代码逻辑。
  3. 在需要同时处理多个异步操作的情况下,Promise.all()方法可以等待多个Promise对象都解析完成。

而async/await则适用于以下情况:

  1. 处理复杂的异步操作,需要嵌套多层级或有多个依赖关系的异步操作。
  2. 在代码的可读性和可维护性上更注重,因为async/await提供了类似同步代码的写法,更容易理解和调试。
  3. 在需要按顺序执行异步操作的情况下,使用await关键字可以确保前一个操作完成后再执行下一个操作。

无论是Promise还是async/await,它们都在现代JavaScript开发中扮演着重要的角色。选择使用哪种方法取决于具体的需求和代码风格。

结论

  • 本文深入探讨了前端开发中的Promise和async/await,这两个工具都为处理异步操作提供了强大的支持。
  • Promise是一种用于处理异步操作的对象,它提供了一组方法来管理异步流程。通过Promise链,我们可以按顺序执行异步操作,并在每个操作完成后传递结果。
  • 而async/await是建立在Promise之上的一种语法糖,旨在简化异步代码的编写和阅读。它允许我们以一种看起来同步的方式编写异步代码,提高了代码的可读性和可维护性。
  • 根据具体的需求和代码风格,选择适合的工具来处理异步操作。在实际开发中,我们可以根据情况灵活使用Promise和async/await,以提高开发效率和代码质量。

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

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

相关文章

XD6500S— LoRa SIP模块

XD6500S是一系列LoRa SIP模块,集成了射频前端和LoRa射频收发器SX1262系列,支持LoRa和FSK调制。收发器SX1262系列,支持LoRa和FSK调制。LoRa技术是一种扩频协议,针对LPWAN 应用的低数据速率、超远距离和超低功耗通信进行了优化。通信…

vscode+python开发之虚拟环境和解释器切换

需求情景: 现在我们要开发多个项目比如:项目A,项目B、项目C,他们每个项目需要依赖不同的库。每个项目依赖的解释器也不一样怎么办? 项目A:需要在python3.7环境运行 依赖aadd3.2库 项目B、需要在python3.11…

云原生微服务架构及实现技术

云原生是一种技术理念和架构方法,它充分利用云计算的优势,将应用程序和基础设施进行优化,以适应云环境的特性。云原生的设计原则主要包括弹性、韧性、安全性、可观测性、灰度等,旨在让企业在云环境中实现轻量、敏捷、高度自动化的…

springboot项目的可执行jar以后台本地服务的方式运行在Windows机器上

文章目录 用到的工具先上一个效果图准备可执行文件注册及启动服务 前段时间遇到一个项目,需要我们提供一个驱动控件,可以以后台服务的方式运行在Windows机器上。开始寻找各种解决办法。 最后发现一个不错的解决方式。分享给大家一下。 用到的工具 链接&…

15分钟,不,用模板做数据可视化只需5分钟

测试显示,一个对奥威BI软件不太熟悉的人来开发数据可视化报表,要15分钟,而当这个人去套用数据可视化模板做报表,只需5分钟! 数据可视化模板是奥威BI上的一个特色功能板块。用户下载后更新数据源,立即就能获…

Spring Cloud Netflix微服务组件-Eureka

目录 CAP理论 注册中心对比 为什么注册中心更适合用AP? 分布式系统AP和CP如何取舍? Eureka核心功能点 Euraka server启动的主线流程 总体流程图 EnableEurekaServer 流程图 EurekaServerAutoConfiguration EurekaServerInitializerConfigurat…

《白帽子讲web安全》笔记

第八章 文件上传漏洞 文件上传漏洞是指用户上传了一个可执行的脚本文件,并通过此脚本文件获得了执行服务器端命令的能力 文件上传后导致的常见安全问题一般有: ❍ 上传文件是Web脚本语言,服务器的Web容器解释并执行了用户上传的脚本&#xf…

准「AI 时代」下,如何衡量程序员的工作效率和生产力?

近 20 家科技、金融和制药公司实施了新的研发效能管理方法,并取得了令人鼓舞的初步结果。 客户报告的产品缺陷减少 20%-30%;员工体验分数提高 20%;客户满意度评分提高 60 个百分点。 大模型和 AIGC 技术催生了软件研发的新范式,也…

推介会如何做好媒体宣传

传媒如春雨,润物细无声,大家好,我是51媒体网胡老师。 推介会是一种专为企业、社会组织和团体、政府等提供的展示自身特点、产品和政策的活动形式,旨在促进交流活动,形成合作,从而带来共同利益。推介会的本…

高压放大器设计要求有哪些内容

设计高压放大器时,需要考虑一系列要求以确保其性能和可靠性。以下是设计高压放大器时的一些重要要求。 输入输出电压范围:高压放大器应具备足够的输入和输出电压范围,以适应特定应用的需求。这包括设计合适的电源供应和电路配置,以…

spark性能调优 | 内存优化

目录 我们先了解一下有哪些内存温馨提示RDD示范(spark版本2.1.1)RDD进行优化Df和Ds进行示范 我们先了解一下有哪些内存 1.storage内存 存储数据,缓存 可预估2.shuffle内存 计算join groupby 不可预估spark1.6之前 静态管理的,spark1.6之…

使用Rust编写爬虫代码来抓取精美的图片

目录 一、引言 二、Rust爬虫框架介绍 三、爬虫代码实现 1、创建Scrapy项目 2、创建Spider 3、定义Item对象 4、修改settings.py文件 5、运行爬虫程序 四、图片抓取与存储 五、优化爬虫性能 六、注意事项 总结 一、引言 网络爬虫是一种自动化的网页访问工具&#x…

python采集小破站视频弹幕

嗨喽~大家好呀,这里是魔王呐 ❤ ~! python更多源码/资料/解答/教程等 点击此处跳转文末名片免费获取 环境使用]: Python 3.8 Pycharm模块使用]: import requests 数据请求 import jieba 分词 import wordcloud 词云 import re 正则通过爬虫程序采集数据 分析数…

口袋参谋:如何找竞争小,优势大的蓝海词?

​ 作为淘宝天猫的中小卖家,99.99%的人都知道流量对于店铺的重要性,如果没有流量的话,店铺是肯定没有销量的。 提高流量的方式有很多种,比如优化宝贝图片、标题、关键词等,由于在淘宝天猫上同一宝贝的竞争力太大了…

2022CCPC绵阳 ACGHM

Dashboard - 2022 China Collegiate Programming Contest (CCPC) Mianyang Onsite - Codeforces C.Catch You Catch Me 题意 思路 首先注意到贡献可以按深度统计,对于每个深度dep,贡献是在dep深度中属于的子树种类数,如果在该深度中子树存在…

PLC电力载波通讯,一种新的IoT通讯技术

前言: PLC-IoT 是 PLC 技术应用在物联场景的创新实践,有效解决电力线路信号干扰、衰减问题,支持 IP 化通信能力,使能终端设备智能化,构建智慧边缘联接。PLC让传统IoT有了更多的连接可能: 电力线通信技术适用的场景包括电力配用电网络、城市智慧路灯、交通路口信号灯、园…

HackTheBox-Starting Point--Tier 2---Archetype

文章目录 一 Archetype测试过程1.1 打点1.2 权限获取1.3 权限提升 二 题目 一 Archetype测试过程 1.1 打点 1.端口扫描 nmap -sV -sC 10.129.192.2522.枚举SMB共享 smbclient -N -L \\\\10.129.192.252\\查看backups,并发现 prod.dtsConfig 文件,在 p…

数据结构:反射

基本概念 反射中的四个类 Class类 Java文件在被编译之后,生成了.class文件,JVM此时解读.class文件,将其解析为java.lang.Class 对象,在程序运行时每个java文件就最终变成了Class类对象的一个实例。通过反射机制应用这个 实例就…

颠覆了!eShop跟随.Net 8迎来重磅升级,微服务架构与GPT的完美结合!

.Net 8正式发布了,发布了诸多重大的新功能、新特性! .Net 8新增的功能带来诸多惊喜,还未一一体验完毕呢,我又发现了跟随.Net 8的发布,eShop也迎来重磅升级! eShop一直以来都是微软官方提供的,…

Istio学习笔记- 服务网格

Istio 服务网格 参考:Istio / Istio 服务网格 Istio 使用功能强大的 Envoy 服务代理扩展了 Kubernetes,以建立一个可编程的、可感知的应用程序网络。Istio 与 Kubernetes 和传统工作负载一起使用,为复杂的部署带来了标准的通用流量管理、遥…