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是个什么,答曰:构造函数

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

失败的逻辑
        //失败的promise
        let 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

定义成功后回调

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

reject

定义失败后回调

        //reject
        Promise.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 = null
            console.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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

网工内推 | 技术支持、解决方案工程师,RHCA认证优先,带薪年假

01 天融信 招聘岗位:售后技术支持工程师 职责描述: 1.负责公司运营商态势安全项目系统远程维护与运营支持工作。 2.负责远程对态势平台、数据探针进行日常巡检,及时发现故障问题,并反馈处置。 3.负责远程支撑态势平台的功能考核&…

k8s是什么

生么是k8s: Kubernetes:8个字母省略,就是k8s 自动部署,自动扩展和管理容器化部署的应用程序的一个开源系统、 k8s是负责自动化运维管理多个容器化程序的集群,是一个功能强大的容器编排工具。 分布式和集群化的分布式进行容器管…

Elasticsearch:无需搜索 “Christmas” 即可找到有关圣诞节的书籍

随着假期的临近,我期待着变得舒适,拿起一本新书,享受轻松的时光。 但是使用搜索栏在线发现图书并不像看起来那么容易......大多数零售搜索引擎仅依赖于关键字搜索,当我们确切地知道我们正在寻找什么书名时,这很好&…

渗透测试 | php的webshell绕过方法总结

目录 1.php的异或运算 2.通过获取注释去绕过 3.利用字符的运算符​​​​​​​ 4.通过end函数代替[] 5.通过常量去绕过 6.字符串拼接双美元符 7.通过函数定义绕过 8.通过类定义,然后传参分割 9.多传参方式绕过​​​​​​​ 10.通过get_defined_function…

教你一分钟弄清屏幕SPI接口名称

相关文章 快速入门ESP32——开发环境配置Arduino IDE 快速入门ESP32——开发环境配置PlatformIO IDE 快速入门ESP32—— platformIO添加开源库和自己的开发库 一分钟弄清屏幕SPI接口名称 前言一、屏幕SPI接口名称二、与单片机连接总结 前言 最近,我在捣鼓CD屏幕的SP…

四川云汇优想教育咨询有限公司抖音电商服务的领航者

四川云汇优想教育咨询有限公司,作为一家在电商服务领域有着深厚底蕴的企业,一直以来都以其卓越的服务质量在业界树立了良好的口碑。尤其是在抖音电商服务方面,云汇优想更是凭借其出色的实力和精准的策略,成为了行业的佼佼者。 在抖…

从企业级负载均衡到云原生,深入解读F5

上世纪九十年代,Internet快速发展催生了大量在线网站,Web访问量迅速提升。在互联网泡沫破灭前,这个领域基本是围绕如何对Web网站进行负载均衡与优化。从1997年F5发布了BIG-IP,到快速地形成完整ADC产品线,企业级负载均衡…

使用Dependency Walker和Process Explorer排查瑞芯微工具软件RKPQTool.exe启动报错问题

目录 1、问题说明 2、使用Dependency Walker查看工具程序的库依赖关系 3、在可以运行的电脑上使用Process Explorer查看依赖的msvcr120.dll和msvcp120.dll库的路径 4、C/C运行时库介绍 5、可以下载安装VC_redist.x86.exe或VC_redist.x64.exe解决系统库缺失问题 C软件异常排…

Apache RocketMQ,构建云原生统一消息引擎

本文整理于 2023 年云栖大会林清山带来的主题演讲《Apache RocketMQ 云原生统一消息引擎》 演讲嘉宾: 林清山(花名:隆基),Apache RocketMQ 联合创始人,阿里云资深技术专家,阿里云消息产品线负…

华为鸿蒙的发展史:从初创到全球领先的历程

自2019年以来,华为的鸿蒙操作系统在全球范围内引发了广泛关注。鸿蒙的发展史见证了中国科技企业的崛起与坚韧,展现了华为对于技术创新的执着追求和坚定信念。本文将带你回顾华为鸿蒙的发展历程,了解这一操作系统如何从初创阶段走向全球领先地…

【Kafka】Kafka客户端认证失败:Cluster authorization failed.

背景 kafka客户端是公司内部基于spring-kafka封装的spring-boot版本:3.xspring-kafka版本:2.1.11.RELEASE集群认证方式:SASL_PLAINTEXT/SCRAM-SHA-512经过多年的经验,以及实际验证,配置是没问题的,但是业务…

三甲基碘硅烷,预计未来几年市场将以稳定的速度增长

三甲基碘硅烷是一种无色透明液体,广泛用作有机化学中的试剂。它用于制备多种有机化合物,包括药物、农用化学品和特种化学品。由于最终用途行业的需求不断增加,预计未来几年全球碘三甲基硅烷市场将以稳定的速度增长。 全球碘三甲基硅烷市场分为…

OpenGL :LearnOpenGL笔记

glfw https://github.com/JoeyDeVries/LearnOpenGL/blob/master/src/1.getting_started/1.1.hello_window/hello_window.cpp #include <glad/glad.h>// 注: GLAD的include文件包含所需的OpenGL头文件(如GL/GL.h) &#xff0c;因此确保在其他需要OpenGL的头文件 (如GLFW…

php 不加后缀访问

实现不带后缀访问php文件的方法&#xff1a;首先在htaccess文件中加入内容“RewriteRule ^(api/token) token.php [L]”&#xff1b;然后通过根目录下的“token.php”来接受“api/token”&#xff1b;最后修改配置文件。 考虑的做法有&#xff1a; HTTP重写技术&#xff0c;让…

仿Yasa算法-睡眠分期,目前五分期86.5%

参考链接 具体内容可见&#xff1a;个人文章 参考代码 The code that was used to train the classifiers can be found on GitHub at: Link 验证数据集 PhysiNet-Haaglanden 选取了其中150例数据&#xff08;剔除了No.98&#xff0c;标签数据长度不匹配&#xff09; 特征…

Shell 脚本应用(四)

正则表达式概述 正则表达式又称正规表达式&#xff0c;常规表达式。在代码中常简写为regex&#xff0c;regexp 或RE.正则表达式 是使用单个字符串来描述&#xff0c;匹配一系列符合某个句法规则的字符串&#xff0c;简单来说&#xff0c;是一种匹配字符串 的方法&#xff0c;通…

Nacos2.1.2改造适配达梦数据库7.0

出于业务需求&#xff0c;现将Nacos改造适配达梦数据库7.0&#xff0c;记录本次改造过程。 文章目录 一、前期准备二、适配流程1、项目初始化2、引入驱动3、源码修改 三、启动测试四、打包测试 一、前期准备 Nacos源码&#xff0c;版本&#xff1a;2.1.2&#xff1a;源码下载…

【Linux驱动】驱动框架的进化 | 总线设备驱动模型

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《Linux驱动》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 目录 &#x1f969;驱动框架的进化&#x1f960;分层&#x1f960;面向对象&#x1f960;编程&am…

爬虫工作量由小到大的思维转变---<第二十八章 Scrapy中间件说明书>

爬虫工作量由小到大的思维转变---&#xff1c;第二十六章 Scrapy通一通中间件的问题&#xff1e;-CSDN博客 前言: (书接上面链接)自定义中间件玩不明白? 好吧,写个翻译的文档点笔记,让中间件更通俗一点!!! 正文: 全局图: 爬虫中间件--->翻译笔记: from scrapy import s…

蓝桥小课堂-平方和【算法赛】

问题描述 蓝桥小课堂开课啦&#xff01; 平方和公式是一种用于计算连续整数的平方和的数学公式。它可以帮助我们快速求解从 1 到 n 的整数的平方和&#xff0c;其中 n 是一个正整数。 平方和公式的表达式如下&#xff1a; 这个公式可以简化计算过程&#xff0c;避免逐个计算…