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

news2024/11/19 3:19:21

文章目录

    • 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.coloradmin.cn/o/1200007.html

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

相关文章

CNN入门实战:猫狗分类

前言 CNN(Convolutional Neural Network,卷积神经网络)是一种深度学习模型,特别适用于处理图像数据。它通过多层卷积和池化层来提取图像的特征,并通过全连接层进行分类或回归等任务。CNN在图像识别、目标检测、图像分割…

ubuntu下tensorrt环境配置

文章目录 一、Ubuntu18.04环境配置1.1 安装工具链和opencv1.2 安装Nvidia相关库1.2.1 安装Nvidia显卡驱动1.2.2 安装 cuda11.31.2.3 安装 cudnn8.21.2.4 下载 tensorrt8.4.2.4 二、编写CMakeLists.txt三、TensorRT系列教程 一、Ubuntu18.04环境配置 教程同样适用与ubuntu22.04…

springcloud电影购票选座网站系统源码

开发技术: jdk1.8,mysql5.7,idea springcloud springboot mybatis vue elementui 功能介绍: 用户端: 登录注册 首页显示搜索电影,轮播图,电影分类,最近上架电影(可…

Linux 内核启动流程

目录 链接脚本vmlinux.ldsLinux 内核启动流程分析Linux 内核入口stext__mmap_switched 函数start_kernel 函数rest_init 函数init 进程 看完Linux 内核的顶层 Makefile 以后再来看 Linux 内核的大致启动流程,Linux 内核的启动流程要比uboot 复杂的多,涉及…

第六章 DNS域名解析服务器

1、DNS简介 DNS(Domain Name System)是互联网上的一项服务,它作为将域名和IP地址相互映射的一个分布式数据库,能够使人更方便的访问互联网。 DNS系统使用的是网络的查询,那么自然需要有监听的port。DNS使用的是53端口…

思科9300交换机使用USB进行升级ISO

一、下载ISO 一、网址 Software Download - Cisco Systems 二、找到型号 四、选择XE 软件 五、进行下载 二、COPY 进 U盘 一、、请注意!如果你的U盘不是Fat32文件格式则交换机读取不了,请先格式化再复制文件。 二、下载后将 bin文件复制到U盘。 1.扩展…

js删除json数据中指定元素

delete 删除数组方法: function removeJSONRows() {var tab {"dataRows": [{"id": 1,"name": "使用部门"},{"id": 2,"name": "车辆走行路线"},{"id": 3,"name": &quo…

【Redis】String字符串类型

上一篇:Redis-key的使用 https://blog.csdn.net/m0_67930426/article/details/134361821?spm1001 .2014.3001.5501 目录 appen (附加) strlen(获取字符串的长度) incr decr getRange(获取字符串) setRange(替…

C语言--求一个 3 X 3 的整型矩阵对角线元素之和

一.题目描述 求一个 3 X 3 的整型矩阵对角线元素之和 二.代码实现 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> int main() {int arr[3][3] { 0 };for (int i 0;i < 3;i){for (int j 0;j < 3;j){ printf("请输入数字&#xff1a;");scanf(&…

卸载本地开发环境,拥抱容器化开发

以前在公司的时候&#xff0c;使用同事准备的容器化环境&#xff0c;直接在 Docker 内进行开发&#xff0c;爽歪歪呀。也是在那时了解了容器化开发的知识&#xff0c;可惜了&#xff0c;现在用不到那种环境了。所以打算自己在本地也整一个个人的开发环境&#xff0c;不过因为我…

SMART PLC MODBUSTCP速度测试

SMART PLC MODBUSTCP通信详细介绍请参看下面文章链接: S7-200SMART PLC ModbusTCP通信(多服务器多从站轮询)_matlab sumilink 多个modbustcp读写_RXXW_Dor的博客-CSDN博客文章浏览阅读6.4k次,点赞5次,收藏10次。MBUS_CLIENT作为MODBUS TCP客户端通过S7-200 SMART CPU上的…

【python】sys-psth和模块搜索路径

我们在导入一个模块的时候&#xff0c;比如说&#xff1a; import math它必然是有搜索路径的&#xff0c;那到底是在哪个目录下面找呢&#xff1f;Python解释器去哪里找这个文件呢&#xff1f;只有找到这个文件才能读取、装载运行该模块文件。 它一般按照如下路径寻找模块文件…

经典OJ题:重排链表

题目&#xff1a; 给定一个链表&#xff0c;在进行重排前&#xff1a; 进行重排链表后&#xff1a; 如上图所示&#xff0c;所谓的重拍链表&#xff0c;就是将第一个节点连接第倒数第一个节点&#xff0c;第二个节点连接倒数第二个节点&#xff0c;以此类推&#xff0c;最后在连…

贝锐蒲公英X1解决远程访问NAS难题

由于经常在外出差和旅游&#xff0c;需要实现即使在外地也能远程登录回去家里的NAS去处理事情或传输文件&#xff0c;因此解决方案之一是搭建一个安全简易的个人私有云。 实施难度 &#xff08;1&#xff09;家庭网络无公网IP&#xff0c;且公网IP价格昂贵&#xff08;2&…

今起不再“没完没了的接龙斗嘴”

今天本“人民体验官”推广人民日报官方微博&#xff08;转央视网&#xff09;的文化产品《数字减负不能比减脂还难》。 截图&#xff1a;来源“人民体验官”推广平台 在时下的一些网络自媒体平台之上&#xff0c;的确存在“越拉越多的群&#xff0c;没完没了的接龙&#xff0c…

在使用Vuex时,5个方法让你保证数据的更新及时性

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

hosts文件修改完成之后无法保存的解决方法

系列文章目录 centos7配置静态网络常见问题归纳_张小鱼༒的博客-CSDN博客 目录 系列文章目录 前言 一、hosts文件为何不能保存的原因 二、Hosts文件无法保存解决方法 1.需要用到hosts的地方 2.具体的操作步骤 总结 前言 Hosts文件是系统中的重要文件&#xff0c;它能屏…

Spring面试题:(五)Spring注解开发@Component,@Autowired,@Bean,@Configuration

Bean基本注解 spring提供注解的版本 Component注解替代bean标签 bean其它属性的相关注解&#xff1a; scope 替代scopelazy 替代lazy-initPostConstruct 替代init-methodPreDestroy 替代destroy-method 使用Component注解的前提是开启注解扫描 衍生注解Repository,Servi…

博客积分上一万一千了

博客积分上一万一千了 充满自信&#xff0c;继续前进。

GCC工具详解【Linux知识贩卖机】

很多人在喧嚣声中登场&#xff0c;也有少数人在静默中退出。 --单独中的洞见2 文章目录 简介程序到可执行文件链接动态链接和静态链接动态库和静态库动态库和静态库的打包打包静态库打包动态库选项 -static 总结 简介 GCC&#xff08;GNU Compiler Collection&#xff09; 是一…