promise的使用和实例方法

前言

异步,是任何编程都无法回避的话题。在promise出现之前,js中也有处理异步的方案,不过还没有专门的api能去处理链式的异步操作。所以,当大量的异步任务逐个执行,就变成了传说中的回调地狱。

        function asyncFn(fn1, fn2, fn3) {setTimeout(() => {//处理第一个异步任务fn1()setTimeout(() => {//处理第二个异步任务fn2()setTimeout(() => {//处理第三个异步任务fn3()},2000)},2000)}, 2000)}function fn1(){console.log('执行1')}function fn2(){console.log('执行2')}function fn3(){console.log('执行3')   }asyncFn(fn1, fn2, fn3)

如果按照这么执行的话,等fn1执行完毕之后,再执行fn2,fn2执行完毕之后再执行fn3,这里只是简单的一个console.log,如果是真实的业务逻辑,那这看着可就太痛苦了。

promise就是用来解决这种问题的。

Promise基础


三种状态

pending代表状态未确定

fulfilled代表成功

rejected代表失败

类似于薛定谔的猫,开箱之前处于一种未知状态,只要你开了,那要么生,要么死,不会再发生更改。

记住,promise的状态是单向流的,一旦变化,永远不会发生更改。

基本用法

promise是个什么,答曰:构造函数

成功的逻辑
        //成功的promiselet prmFn1 = new Promise((resolve,jeject)=>{setTimeout(()=>{//模拟执行一个很消耗时间的任务resolve('我是成功的值')},5000)})prmFn1.then(resolve=>{console.log(resolve)    //5秒后输出:我是成功的值})

失败的逻辑
        //失败的promiselet prmFn2 = new Promise((resolve,reject)=>{setTimeout(()=>{reject('我是失败的原因')},5000)})console.log(prmFn2,'失败任务还没有开始执行',prmFn2)prmFn2.then(resolve=>{//成功才回被调用},reject=>{console.log('失败了被调用',reject)console.log('失败任务处理完毕',prmFn2)})

 

这里发生了什么:

1.通过new Promise构造函数创建了一个promise函数,参数是一个函数。

2.这个函数有两个参数,一个是resolve函数,一个是reject函数,resolve代表异步任务成功需要调用的,reject函数代表异步任务失败了需要调用的。

3.promise创建了之后,会变成一个有状态的对象,这个对象内有一个属性then,then是一个函数,then函数中有两个参数,这两个参数都是函数,参数1一个是专门用来处理成功的,参数2专门用来处理失败情况的。

4.参数1函数的参数,就是在promise中resolve(value)中的value,参数2函数的参数,就是promise中reject(errorReason)中的errorReason。

感觉很绕是不是,这里就是函数式编程的经典范例,也是promise对于很多初级前端来说,很懵的地方。

解决方案:多学多练多理解

promise对象的方法

promise是一个构造函数,但是同时也是一个对象,这个对象中存在很多用于处理不同业务的方法,所以可以称promise为函数对象

resolve

定义成功后回调

        //resolvePromise.resolve('成功值').then(res => {console.log(res, 'resolve的使用')})//等同于new Promise((resolve, reject) => {resolve('成功值')}).then(res => {console.log(res, 'resolve的使用')})

reject

定义失败后回调

        //rejectPromise.reject('失败值').then(res => {console.log(res, '不会走成功')}, rej => {console.log(rej, '会走失败')})//等同于new Promise((resolve, reject) => {reject('失败值')}).then(res => {console.log(res, '不会走成功')}, rej => {console.log(rej, '会走失败')})

then

根据状态值进行异步处理

当一个promise执行到then的时候,说明这个promise对象的状态值已经确定了,也就是只要执行到then方法里面,就说明前面的异步执行完成了,你可以根据返回的状态值进行异步的操作了。

then方法是promise的核心方法。

then是一个函数,接受两个参数,这两个参数都是函数,参数一处理成功回调,参数2处理失败回调

上面的代码都已经演示了,这里就不写了

catch

promise内发生意外报错回调处理

        let prm = new Promise((resolve, reject) => {let a = nullconsole.log(a.a)resolve('成功')})prm.then(res => {console.log(res, '进入then方法')}).catch(error => {console.log(error, '进入error')})

 all

所有异步都执行完毕后得到结果

异步都成功

        let prm1 = new Promise((resolve, reject) => {setTimeout(() => {resolve('执行prm1成功')}, 3000)})let prm2 = new Promise((resolve, reject) => {setTimeout(() => {resolve('执行prm2成功')}, 1000)})let prm3 = new Promise((resolve, reject) => {setTimeout(() => {resolve('执行prm3成功')}, 5000)})Promise.all([prm1, prm2, prm3]).then(res => {console.log(res, '三个都执行完毕')})

 异步中有失败

        let prm1 = new Promise((resolve, reject) => {setTimeout(() => {resolve('执行prm1成功')}, 3000)})let prm2 = new Promise((resolve, reject) => {setTimeout(() => {resolve('执行prm2成功')}, 1000)})let prm3 = new Promise((resolve, reject) => {setTimeout(() => {reject('执行prm3失败')}, 5000)})Promise.all([prm1, prm2, prm3]).then(res => {console.log(res, '三个都执行完毕--成功')}, rej => {console.log(rej, '三个都执行完毕--有不成功')})

allSettled

all方法能获取所有任务都成功之后的值,但是如果多个任务有成功有失败,就无法全部获取所有状态,但是allSettled可以做到

        //allSettled方法let pr1 = new Promise((resolve,reject)=>{setTimeout(()=>{resolve('pr1成功')},2000)})let pr2 = new Promise((resolve,reject)=>{setTimeout(()=>{resolve('pr2失败')},3000)})let pr3 = new Promise((resolve,reject)=>{setTimeout(()=>{resolve('pr3成功')},3000)})Promise.allSettled([pr1,pr2,pr3]).then(res=>{console.log(res,'获取所有状态')})

 

 race

获取多个异步中最先执行完毕的结果

成功的情况

        //race方法let prm1 = new Promise((resolve, reject) => {setTimeout(() => {resolve('执行prm1成功')}, 3000)})let prm2 = new Promise((resolve, reject) => {setTimeout(() => {resolve('执行prm2成功')}, 1000)})let prm3 = new Promise((resolve, reject) => {setTimeout(() => {reject('执行prm3失败')}, 5000)})Promise.race([prm1, prm2, prm3]).then(res => {console.log(res, '成功逻辑')},rej => {console.log(rej, '失败逻辑')})

 失败的情况

        let prm1 = new Promise((resolve, reject) => {setTimeout(() => {resolve('执行prm1成功')}, 3000)})let prm2 = new Promise((resolve, reject) => {setTimeout(() => {reject('执行prm2失败')}, 1000)})let prm3 = new Promise((resolve, reject) => {setTimeout(() => {reject('执行prm3失败')}, 5000)})Promise.race([prm1, prm2, prm3]).then(res => {console.log(res, '成功逻辑')},rej => {console.log(rej, '失败逻辑')})

 any

有一个成功,就是成功。全都失败,就是失败

        //any方法let pr1 = new Promise((resolve, reject) => {setTimeout(() => {resolve('pr1成功')}, 2000)})let pr2 = new Promise((resolve, reject) => {setTimeout(() => {resolve('pr2失败')}, 3000)})let pr3 = new Promise((resolve, reject) => {setTimeout(() => {resolve('pr3失败')}, 3000)})Promise.any([pr1,pr2,pr3]).then(res=>{console.log(res,'成功')})Promise.any([pr2,pr3]).then(res=>{console.log(res,'失败')})

 

 finally

不管一个promise任务执行成功还是失败,执行完毕后都会进入这个方法

        //finally方法//成功let prm4 = new Promise((resolve,reject)=>{setTimeout(()=>{resolve('成功的值')},2000)})prm4.then(res=>{console.log(res,'成功')}).finally(val=>{console.log(val,'finally方法')})//失败let prm5 = new Promise((resolve,reject)=>{setTimeout(()=>{reject('失败原因')},2000)})prm5.catch(rej=>{console.log(rej,'失败')}).finally(val=>{console.log(val,'finally方法')})

项目中实际应用和注意事项

在当今的前端项目中,基本不会说用不到promise的,最常见的还是前后端数据交互,例如axios,fetch等请求都是通过promise封装后的,返回的值都是promise。

在项目实际场景中,会出现promise的回调链,下一个结果依赖上一个结果的返回值,形成异步任务的依赖关系。开发者需要去处理一个比较重要的问题,叫做中断promise链

中断promise链
        //层层依赖形成执行链Promise.resolve('初始化成功值').then(res => {return new Promise(resolve => {setTimeout(() => {console.log(res)resolve('第一层返回成功值')}, 2000)})}).then(res => {return new Promise(resolve => {setTimeout(() => {console.log(res)resolve('第二层返回成功值')}, 2000)})}).then(res => {return new Promise(resolve => {setTimeout(() => {console.log(res)resolve('第三层返回成功值')}, 2000)})})

效果如下

我们可以根据每个任务的结果值去判定业务逻辑,是否需要中断后续的执行链条

代码改造如下

        //中断promise链Promise.resolve('初始化成功值').then(res => {return new Promise(resolve => {setTimeout(() => {console.log(res)// resolve('第一层返回成功值')resolve('中断标识')}, 2000)})}).then(res => {if(res ==='第一层返回值'){return new Promise(resolve => {setTimeout(() => {console.log(res)resolve('第二层返回成功值')}, 2000)})}else{console.log('进入中断链方法')//返回一个空的promise,就完成了中断return new Promise(()=>{})}}).then(res => {return new Promise(resolve => {setTimeout(() => {console.log(res)resolve('第三层返回成功值')}, 2000)})})

总结

三种状态:pending,fulfilled,rejected。分别代表待定,成功和失败。一旦修改,无法改变

九种方法:

resolve代表返回成功状态

reject代表返回失败状态

then是执行完毕进入的回调

catch是执行出错进入的回调

all代表全部成功,返回的是所有异步任务的成功值

allSettled代表全部执行完毕,即使不成功,也会返回全部异步任务的值

race代表获取先执行完毕的异步值

any代表有一个成功,就是成功。全都失败,就是失败

finnally代表你不管成功还是失败,都得来我这里。

实际应用:

多了去了,很多第三方包都会用到,前后端交互必备

中断执行链:

返回一个空的promise

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

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

相关文章

WPF RelativeSource

RelativeSource 类在 WPF 中提供了以下几种模式&#xff1a; RelativeSource Self&#xff1a;指定当前元素作为相对源。可以在当前元素的属性中绑定到自身的属性。 示例&#xff1a; <TextBlock Text"{Binding Text, RelativeSource{RelativeSource Self}}" /&…

element步骤条<el-steps>使用具名插槽自定义

element步骤条使用具名插槽自定义 步骤条使用具名插槽: <el-steps direction"vertical" :active"1"><el-step><template slot"description">//在此处可以写你的插槽内容</template>/el-step> </el-steps>步骤…

STM32 cubeMX 直流电机控制风扇转动

本文使用的是 HAL 库。 文章目录 前言一、直流电机介绍二、直流电机原理图三、直流电机控制方法四、STM32CubeMX 配置直流电机五、代码编写总结 前言 实验开发板&#xff1a;STM32F051K8。所需软件&#xff1a;keil5 &#xff0c; cubeMX 。实验目的&#xff1a;了解 直流电机…

远程宠物喂食系统:开启宠物护理新纪元

智能化远程宠物喂食系统正在革新宠物业&#xff0c;宠物用品店、宠物托管服务商&#xff0c;宠物健康检测机构、宠物社区运营方等相关企业可能将因此取得更高效的运营&#xff0c;更深入的客户关系。这个系统不仅增强了宠物行业的智能化元素&#xff0c;还通过其精确和有效的管…

软件测试自学还是报班好?

如果你学软件测试&#xff0c;是以就业为目的&#xff0c;而且是以高薪就业为目的&#xff0c;那我们就要去反推&#xff0c;为了这个目标&#xff0c;我们要去做什么事情。 为了“将高薪就业为目的&#xff0c;我们要做什么事情”阐述清楚&#xff0c;本文行文结构如下&#x…

并发代码中的错误处理挑战

克服并发编程中的复杂性 并发编程可能是增加软件系统效率和响应性的强大技术。它使多个工作负载能够同时运行&#xff0c;充分利用了现代多核CPU。然而&#xff0c;强大的能力伴随着巨大的责任&#xff0c;良好的错误管理是并发编程中的主要任务之一。 并发代码的复杂性 并发…

找不到UnityEngine.UI解决方案

重新安装Visual Studio 后&#xff0c;使用unity找不到UnityEngine.UI解决方案 关键是在unity里需要设置一下 这个路径 C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE

【centos】【golang】安装golang

下载安装包 方法1&#xff1a; 打开 https://go.dev/dl/ &#xff1b;点击下载golang的安装包&#xff1b;再使用ssh传到centos上&#xff08;略&#xff09; 方法2&#xff1a;能使用Google就可以这样 wget https://dl.google.com/go/go1.21.5.linux-amd64.tar.gz解压安装包…

GoLang - select

文章目录 Go 语言 select 语句1、概述2、语法3、简单实例4、实现原理实现原理执行流程scase 数据结构判断某个 scase 属于什么操作 5、应用场景多通道读取多通道写入超时控制 Go 语言 select 语句 1、概述 select 是 Go 中的一个控制结构&#xff0c;类似于 switch 语句&…

『CV学习笔记』NVIDIA NVLink和NVSwitch介绍

NVIDIA NVLink和NVSwitch介绍 文章目录 一. 全球最大GPU背后秘密:NVLink和NVSwitch如何实现NVIDIA DGX的超强功力1.1. 单GPU1.2. 双GPU(PCIe和NVLink)1.2.1. PCIe1.2.2. NVLink1.3. GPU \times

快速实现Modbus和Profinet互转的方案

为了快速实现将Modbus信号转换为Profinet信号的畅通无阻&#xff0c;我们可以使用Modbus转Profinet网关&#xff08;XD-MDPN100/200&#xff09;。Modbus转Profinet网关&#xff08;XD-MDPN100/200&#xff09;可以实现快速的协议转换&#xff0c;将Modbus信号转换为Profinet信…

OMSET隐私政策

隐私政策 本客户端尊重并保护所有使用本客户端用户的个人隐私权。但本客户端将以高度的严谨态度&#xff0c;审慎对待个人信息。我们制定本“隐私政策”并希望您在使用本客户端及相关服务前仔细阅读并理解本隐私政策&#xff0c;以便做出自愿的适当的选择。若您同意该隐私政策说…

12.26

key_it.c #include"key_it.h" void led_init() {// 设置GPIOE/GPIOF时钟使能RCC->MP_AHB4ENSETR | (0x3 << 4);// 设置PE10/PE8/PF10为输出模式GPIOE->MODER & (~(0x3 << 20));GPIOE->MODER | (0x1 << 20);GPIOE->MODER & (~…

深入理解pytest.ini文件的配置与使用

在Python的测试框架中&#xff0c;pytest是一个广受欢迎的工具。它提供了丰富的功能和灵活的配置选项&#xff0c;使得编写和执行测试用例变得更加简单和高效。其中&#xff0c;pytest.ini文件是pytest的一个重要配置文件&#xff0c;通过配置pytest.ini文件&#xff0c;我们可…

Ubuntu 22.04.3 Server 设置静态IP 通过修改yaml配置文件方法

目录 1.查看网卡信息 2.修改yaml配置文件 3.应用新的网络配置 4.重新启动网络服务 文章内容 本文介绍Ubuntu 22.04.3 Server系统通过修改yaml配置文件配置静态 ip 的方法。 1.查看网卡信息 使用ifconfig命令查看网卡信息获取网卡名称​ 如果出现Command ifconfig not fo…

Oracle动态性能视图 v$parameter 和 v$parameter2 的区别

v$parameter 的说明见这里&#xff1a; V$PARAMETER displays information about the initialization parameters that are currently in effect for the session. v$parameter2 的说明见这里&#xff1a; V$PARAMETER2 displays information about the initialization paramet…

alertmanage调用企业微信告警(k8s内部署)

一、前言 alertmanage调用企业微信应用告警会比直接使用钉钉告警更麻烦一点&#xff0c;调用企业微信应用告警需要在应用内配置企业可信ip&#xff0c;不然调用企业微信接口就会报错&#xff0c;提示ip地址有风险 二、部署 先自行创建企业微信&#xff0c;再使用管理后台创建应…

企业网银 相关注意事项合辑 不断更新中...

山西省农村信用社 (shanxinj.com) 企业网上银行 山西省农村信用社 企业网上银行&#xff0c;注意事项&#xff1a; 1、通过安装【网银向导】修复网银安全控件、密码控件等&#xff1b; 2、登录界面无Ukey验证&#xff0c;也就是输入企业号、用户编号、登录密码及验证码即可进…

Java:为什么“byte 0XFF”可以转为无符号数据类型

在 Java 中&#xff0c;字节是有符号的数据类型&#xff0c;其取值范围是 -128 到 127。当执行与操作 & 时&#xff0c;如果字节的最高位是1&#xff08;即负数&#xff09;&#xff0c;则结果仍然是一个有符号的整数&#xff0c;可能导致不正确的结果。 通过使用 & 0…

树莓派,opencv,Picamera2利用舵机云台追踪人脸(PID控制)

一、需要准备的硬件 Raspiberry Pi 4b两个SG90 180度舵机&#xff08;注意舵机的角度&#xff0c;最好是180度且带限位的&#xff0c;切勿选360度舵机&#xff09;二自由度舵机云台&#xff08;如下图&#xff09;Raspiberry CSI 摄像头 组装后的效果&#xff1a; 二、项目目…