ES6 - promise.all和race方法的用法详解

文章目录
- 一、前言
 - 二、`Promise.all()`
 - 1,第一句:Promise.all()方法接受一个数组作为参数,且每一个都是 Promise 实例
 - 2,第二句:如果不是,就会先调Promise.resolve方法,将参数转为 Promise 实例再进一步处理
 - 3,第三句:Promise.all()方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例
 
- 三、`Promise.race()`
 - 四、总结
 
一、前言
谈谈你对Promise的理解?
答:Promise用来解决异步回调问题,由于js是单线程的,很多异步操作都是依靠回调方法实现的,这种做法在逻辑比较复杂的回调嵌套中会相当复杂;也叫做回调地狱;
promise用来将这种繁杂的做法简化,让程序更具备可读性,可维护性;promise内部有三种状态,
pending,fulfilled,rejected;pending表示程序正在执行但未得到结果,即异步操作没有执行完毕,fulfilled表示程序执行完毕,且执行成功,rejected表示执行完毕但失败;这里的成功和失败都是逻辑意义上的;并非是要报错。其实,promise和回调函数一样,都是要解决数据的传递和消息发送问题,promise中的then一般对应成功后的数据处理,catch一般对应失败后的数据处理。
(1) All方法
他是Promise对象中的方法 他是一次执行多个promise;
(2) race方法
他也是Promise对象中的方法 他是执行最快的那个promise;All方法可以触发多个 ,他只是触发一个 但是在多个promise中做出一个选择,选择出一个运行最快的promise;
二、Promise.all()
 
Promise.all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。
const p = Promise.all([p1, p2, p3]);
 
上面代码中,Promise.all()方法接受一个数组作为参数,p1、p2、p3都是一个 Promise 实例,如果不是,就会先调Promise.resolve方法,将参数转为 Promise 实例再进一步处理。另外,Promise.all()方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。
该怎么理解这句话呢,下面将逐句说明;
1,第一句:Promise.all()方法接受一个数组作为参数,且每一个都是 Promise 实例
这句话说明了 Promise的标准用法:
即传入一个数组,期望数组里面的每一项都是一个promise实例;如下使用:
	 ## 1,先定义几个异步函数,此处用定时器 let p1 = new Promise((resolve, reject) => {setTimeout(function () {resolve("success_1");}, 1000);});let p2 = new Promise((resolve, reject) => {setTimeout(function () {resolve("success_2");}, 2000);});let p3 = new Promise((resolve, reject) => {setTimeout(function () {resolve("success_3");}, 3000);});## 2,使用Promise.all([p1, p3, p2]).then((result) => {console.log(result); // 结果为:['success_2', 'success_3', 'success_1']}).catch((error) => {console.log(error); });
 
等待几秒后,结果打印为:
['success_2', 'success_3', 'success_1']
 
Promise.all接收到的数组顺序是一致的,即p3的结果在p2的前面,即便p3的结果获取的比p2要晚;这带来了一个很大的好处;
在前端开发请求数据的过程中,偶尔会遇到发送多个请求并根据请求顺序获取和使用数据的场景,使用Promise.all毫无疑问可以解决这个问题;
Promise.all 里面所有的promise都执行成功(fulfilled状态)才会返回成功的数组,只要有一个失败(reject),就会被catch回调捕获;如下失败的情况:
 	 let p1 = new Promise((resolve, reject) => {setTimeout(function () {resolve("success_1");}, 1000);});let p2 = new Promise((resolve, reject) => {setTimeout(function () {resolve("success_2");}, 2000);});## 1,失败的promsielet p3 = Promise.reject("失败");## 2,执行Promise.all([ p1,p2,p4]).then((result) => {console.log(result);}).catch((error) => {console.log("error:",error); // 失败了,打印 '失败'}); 
执行结果如下:
error:失败
 
说明只要其中有一个失败就返回失败数据;
注意:如果作为参数的 Promise 实例,自己定义了catch方法,那么它一旦被rejected,并不会触发Promise.all()的catch方法。
请务必记住:promise.all 接收的promise数组,是按顺序且同步执行的
2,第二句:如果不是,就会先调Promise.resolve方法,将参数转为 Promise 实例再进一步处理
如果我们传入的数组项不是promsie对象,还会正常执行吗:
(1):传入的数组每一项都不是 promise实例
		## 直接传 几个number类型Promise.all([1, 2, 3]).then((res) => {console.log("res:", res); // [1,2,3]}).catch((err) => {console.log("err:", err);});
 
执行结果:
[1,2,3]
 
可以看出:如果传入数组中的每一项都不是 promise对象 则会原封不动的让 resolve()函数返回 ;
 既拿到什么就返回什么;
(2)第二种:传入的数组中既有promise实例 也有不是的
如下:我传了number 1,2 和两个promise实例 p2,p1;
     let p1 = new Promise((resolve, reject) => {setTimeout(function () {resolve("success_1");}, 1000);});let p2 = new Promise((resolve, reject) => {setTimeout(function () {resolve("success_2");}, 2000);});Promise.all([1, 2, p2, p1]).then((res) => {console.log("res——2:", res); //  [1, 2, 'success_2', 'success_1']}).catch((err) => {console.log("err:", err);}); 
执行结果:
 [1, 2, 'success_2', 'success_1']
 
可以看出:执行的顺序是先返回非promise, 再执行p2,p1这两个promise对象,然后也按照顺序并返回结果;
3,第三句:Promise.all()方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例
怎么理解这句话呢,说明all方法传入的不一定是数组,还可能是支持遍历(Iterator)的其他数据结构;那这个数据结构不就是ES6新增的 Set集合吗;
概述Set集合:
Set也是ES6的数据结构。特点是无序不重复,它类似于数组,但是成员的值都是唯一的,没有重复的值。Set本身是一个构造函数,用来生成Set数据结构,Set函数可以接受一个数组作为参数,用来初始化。
使用Promise.all()传入Set集合:
      let p1 = new Promise((resolve, reject) => {setTimeout(function () {resolve("success_1");}, 1000);});let p2 = new Promise((resolve, reject) => {setTimeout(function () {resolve("success_2");}, 2000);});let p3 = new Promise((resolve, reject) => {setTimeout(function () {resolve("success_3");}, 3000);});## 1,定义Set集合let myMap = new Set([p2, p1, p3]); console.log("myMap:", myMap); // Set(3) {Promise, Promise, Promise}## 2,all方法传入Set集合Promise.all(myMap).then((myMapRes) => {console.log("myMapRes:", myMapRes); //   ['success_2', 'success_1', 'success_3']}).catch((err) => {console.log("err:", err);});
 
执行结果:
['success_2', 'success_1', 'success_3']
 
可以看出,执行的结果是和数组的方式是一样的;
三、Promise.race()
 
Promise.race()方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。
const p = Promise.race([p1, p2, p3]);
 
Promise.race是赛跑的意思,也就是说Promise.race([p1, p2, p3])里面的结果哪个获取的快,就返回哪个结果,不管结果本身是成功还是失败。
使用场景:
有时我们比如说有好几个服务器的好几个接口都提供同样的服务,我们不知道哪个接口更快,就可以使用Promise.race,哪个接口的数据先回来我们就用哪个接口的数据;
代码如下:
      let p1 = new Promise((resolve, reject) => {setTimeout(function () {resolve("success_1");}, 1000);});let p2 = new Promise((resolve, reject) => {setTimeout(function () {resolve("success_2");}, 2000);});let p3 = new Promise((resolve, reject) => {setTimeout(function () {resolve("success_3");}, 3000);});## 调用race方法Promise.race([p2,p1,p3]).then(res=>{console.log("resRace:",res); // resRace: success_1}).catch(err=>{console.log("errRace:",err);})
 
执行结果:
resRace: success_1
 
p1确实是执行最快的,返回执行最快的那个promsie的resolve结果,其他的promsie将不会再管了;
当然,如果最快的这个执行promsie失败了,也是会走catch回调的;
四、总结
- promise.all 接收的promise数组,总是按顺序且同步执行并返回的;只要有一个promise失败,最终状态就是失败的(reject)就会被catch捕获。
 - promise.race 也接收promise数组,总是返回执行最快的那一个,其他promise的状态并不关心。
 
相关文章:
ES6 - promise.all和race方法的用法详解
文章目录 一、前言二、Promise.all()1,第一句:Promise.all()方法接受一个数组作为参数,且每一个都是 Promise 实例2,第二句:如果不是,就会先调Promise.resolve方法,将参数转为 Promise 实例再进…...
CAD .NET 15.0 企业版 Crack
CAD .NET 15.0 企业版 企业版 企业版 企业版 企业版 Updated: June 14, 2023 | Version 15.0 NEW CAD .NET is a library for developing solutions in .NET environment. It supports AutoCAD DWG/ DXF, PLT and other CAD formats. The library can be used in a wide rang…...
苍穹外卖day07——缓存菜品套餐+购物车功能实现
缓存菜品——需求设计与分析 问题说明 用户访问量过大带来的一个直接效果就是响应速度慢,使用体验下降。 实现思路 使用redis缓存菜品数据,减少数据库查询操作。 页面展示上基本就是同一个分类在同一页,所以key-value结构可以使用不同的分…...
学习笔记|大模型优质Prompt开发与应用课(二)|第四节:大模型帮你写代码,小白也能做程序
文章目录 01软件开发产业趋势与技术革新软件开发产业趋势与技术革新技术性人才很受欢迎软件开发产业趋势与技术革新技术门槛越来越低 02 大模型驱动的软件开发需求分析prompt 产品设计开发和测试prompt输出回复promptpromptprompt回复 发布和部署promptprompt 维护和更新prompt…...
建造者设计模式 + 高阶函数 => DSL
该设计模式适用于创建复杂对象,该复杂对象通常是由各个部分的子对象用一定的算法或者步骤构成,针对每个子对象内部算法和步骤通常是稳定的,但是该复杂对象的确实由于不同的需求而选择使用不同的子对象进行组装。对于构建该复杂的对象…...
重学C++系列之智能指针简单介绍
一、什么是智能指针 在使用堆内存时,就像使用栈内存空间一样,可以实现自释放的功能,智能指针在C库中也是类模板之一。 二、智能指针有几种 有四种。auto_ptr, unique_ptr, shared_ptr, weak_ptr 其中后三个是C11支持,第一个已经被…...
LabVIEW开发航天器动力学与控制仿真系统
LabVIEW开发航天器动力学与控制仿真系统 计算机仿真是工程设计和验证的非常有用的工具。它节省了大量的时间、金钱和精力。航天器动力学与控制仿真系统由LabVIEW程序开发,它是模拟航天器等动态系统的有用工具。还可轻松与硬件连接并输出真实信号。 项目采用系统工…...
享元模式——实现对象的复用
1、简介 1.1、概述 当一个软件系统在运行时产生的对象数量太多,将导致运行代价过高,带来系统性能下降等问题。例如,在一个文本字符串中存在很多重复的字符,如果每个字符都用一个单独的对象来表示,将会占用较多的内存…...
【GreenDao】关联表实现,父表关联多个子表
要在GreenDao中实现温湿度采集器表和采集数据表的关联,并在删除温湿度表时同时删除对应的采集数据,可以按照以下步骤进行操作: 在GreenDao的实体类中定义温湿度采集器表(Parent Table)和采集数据表(Child …...
python网站创建005:数据交互
目标:本章讲解不同控件下, 数据在前端和后端之间的交互 控件有: 输入框 密码输入框 单选框 多选框 下拉框 多行文本框 不同控件中如何将数据传入后端?请看一下html代码 <!DOCTYPE html> <html> <head><meta …...
golang 字符串操作、处理
一、golang的字符串长度 1. len()内置系统函数,计算字符串结果是字符串的字节长度,不是字符长度 //1.ASCII字符串长度(字节长度) str1 : "wo ai zhong guo" fmt.Println(len(str1)) //15//2.带中文的字符串长度&…...
Nginx配置WebSocket反向代理
1、WebSocket协议  WebSocket协议相比较于HTTP协议成功握手后可以多次进行通讯,直到连接被关闭。但是WebSocket中的握手和HTTP中的握手兼容,它使用HTTP中的Upgrade协议头将连接从HTTP升级到WebSocket。这使得WebSocket程序可以更容易的使用现已存在的…...
devops(后端)
1.前言 该devpos架构为gitlabjenkinsharbork8s,项目是java项目,流程为从gitlab拉取项目代码到jenkins,jenkins通过maven将项目代码打成jar包,通过dockerfile构建jdk环境的镜像并把jar包放到镜像中启动,构建好的镜像通…...
Ubuntu安装企业微信
Ubuntu安装企业微信_ubuntu下安装企业微信_星光2020的博客-CSDN博客 在Ubuntu环境安装企业微信可以参考 https://github.com/zq1997/deepin-wine 所述的方法 首先运行 $ wget -O- https://deepin-wine.i-m.dev/setup.sh | sh 然后就可以像安装其它软件一样安装企业微信或其它…...
Prometheus 的应用服务发现及黑河部署等
目录 promtool检查语法 部署Prometheus Server 检查语法是否规范 部署node-exporter 部署Consul 直接请求API进行服务注册 使用register命令注册服务(建议使用) 单个和多个注册,多个后面多加了s 在Prometheus上做consul的服务发现 部署…...
JAVA SE -- 第十二天
(全部来自“韩顺平教育”) 常用类 一、包装类 1、包装类的分类 ①针对八种基本数据类型相应的引用类型--包装类 ②有了类的特点,就可以调用类中的方法 ③ 基本数据类型包装类booleanBooleancharCharacterbyteByteshortShortintInteger…...
实战:工作中对并发问题的处理
大家好,我是 方圆。最近在接口联调时发生了数据并发修改问题,我想把这个问题讲解一下,并把当时提出的解决方案进行实现,希望它能在大家以后在遇到同样的问题时提供一些借鉴和思考的方向。原文还是收录在我的 Github: enthusiasm 中…...
腾讯云Cloud Studio:基于Claude快速完成Excel工资自动核算
目录 1 什么是Cloud Studio?2 注册与代码管理2.1 账号注册2.2 Git关联 3 实战:Excel工资自动核算3.1 创建项目与配置3.2 “念咒师”Claude GPT3.3 代码编写与运行 1 什么是Cloud Studio? Cloud Studio是腾讯云为开发者提供的一个基于浏览器的…...
Spring Boot OAuth2 快速入门示例
系统要求 Spring Authorization Server 需要JDK1.8及以上版本。 项目搭建 使用在线项目初始化器 https://start.spring.io/ 生成项目[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ljKbMI4H-1690726855433)(images/screenshot_1690602511482.png)…...
MethodInterceptor
目录 1 MethodInterceptor 1.1 HandleSync 1.2 HandleException 1.3 /// This will be called via Reflection MethodInterceptor HandleSync private void HandleSync(IReadOnlyList<MethodFilterAttribute> filterAttributes, IReadOnlyList<ExceptionFilte…...
CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了  先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
【项目实战】通过多模态+LangGraph实现PPT生成助手
PPT自动生成系统 基于LangGraph的PPT自动生成系统,可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析:自动解析Markdown文档结构PPT模板分析:分析PPT模板的布局和风格智能布局决策:匹配内容与合适的PPT布局自动…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...
IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...
laravel8+vue3.0+element-plus搭建方法
创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...
代码随想录刷题day30
1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...
JVM 内存结构 详解
内存结构 运行时数据区: Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器:  线程私有,程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。  每个线程都有一个程序计数…...
LLMs 系列实操科普(1)
写在前面: 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容,原视频时长 ~130 分钟,以实操演示主流的一些 LLMs 的使用,由于涉及到实操,实际上并不适合以文字整理,但还是决定尽量整理一份笔…...
如何更改默认 Crontab 编辑器 ?
在 Linux 领域中,crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用,用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益,允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...
