promise的使用和实例方法

news2024/11/20 22:40:57

前言

异步,是任何编程都无法回避的话题。在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

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

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

相关文章

12.26_黑马数据结构与算法笔记Java

目录 243 图 Floyd Warshall 算法实现2 244 图 Floyd Warshall 算法实现3 245 图 Floyd Warshall 算法实现4 246 图 最小生成树 Prim 247 图 最小生成树 Kruskal 248 图 并查集 1 249 图 并查集 2 250 图 并查集 路径压缩 251 图 并查集 UnionBySize 252 贪心算法 介绍…

vue3开发一个todo List

创建新的 Vue 3 项目: 按装vue3的 工具 npm install -g vue/cli创建一个新的 Vue 3 项目: vue create vue3-todolist进入项目目录: cd vue3-todolist代码: 在项目的 src/components 目录下,创建一个新的文件 Todo…

蓝桥杯c/c++程序设计——冶炼金属

冶炼金属 问题描述 小蓝有一个神奇的炉子用于将普通金属 O 冶炼成为一种特殊金属 X。这个炉子有一个称作转换率的属性 V,V 是一个正整数,这意味着消耗 V 个普通金属 O 恰好可以冶炼出一个特殊金属 X,当普通金属 O 的数目不足 V 时&#xff0…

基于yolov8,制作停车位计数器(附源码)

大家好,YOLO(You Only Look Once) 是由Joseph Redmon和Ali开发的一种对象检测和图像分割模型。 YOLO的第一个版本于2015年发布,由于其高速度和准确性,瞬间得到了广大AI爱好者的喜爱。 Ultralytics YOLOv8则是一款前沿、最先进(SOTA)的模型&a…

随记-语义分割

Semantic Segmentation 什么是语义分割全卷积网络FCN摘要 什么是语义分割 语义分割 Semantic Segmentation 旨在对图像的每个像素进行分类,将其分配给预定义的语义类别。 (检测图像中的物体并按属性分类) 实例分割 Instance Segmentation 实…

Vue框架引入Element-Ui

首先已经创建好了 Vue 框架,安装好了 node.js。 没有完成的可按照此博客搭建:搭建Vue项目 之后打开终端,使用命令。 1、命令引入 npm i element-ui -S2、package.json 查看版本 在 package.json 文件里可查看下载好的依赖版本。 3、在 ma…

按照不同产品类型,划片机主要可以分为如下几个类别

随着科技的不断发展,划片机在半导体封装行业中的应用越来越广泛。根据不同的产品类型,划片机主要可以分为砂轮划片机和激光划片机两个类别。本文将详细介绍这两类划片机的特点和应用。 一、砂轮划片机 砂轮划片机是综合了水气电、空气静压高速主轴、精密…

【Vulnhub 靶场】【Funbox: Scriptkiddie】【非常简单】【20210720】

1、环境介绍 靶场介绍:https://www.vulnhub.com/entry/funbox-scriptkiddie,725/ 靶场下载:https://download.vulnhub.com/funbox/Funbox11.ova 靶场难度:简单 发布日期:2021年07月20日 文件大小:1.3 GB 靶场作者&…

Windows无法安装edge 无法连接Internet

如果出现以上问题,或者Edge浏览器无法更新,提示防火墙错误之类的都可以解决问题。 下载以下证书文件并导入即可解决问题。 MicrosoftRootCertificateAuthority2011.cer

《PCI Express体系结构导读》随记 —— 第I篇 第1章 PCI总线的基本知识(4)

接前一篇文章:《PCI Express体系结构导读》随记 —— 第I篇 第1章 PCI总线的基本知识(3) 1.1 PCI总线的组成 PCI总线作为处理器系统的本地总线,是处理器系统的一个组成部件。因此,讲述PCI总线的组成结构,不…

DataFunSummit:2023年数据湖架构峰会-核心PPT资料下载

一、峰会简介 现今,很多企业每天都有PB级的数据注入到大数据平台,经过离线或实时的ETL建模后,提供给下游的分析、推荐及预测等场景使用。面对如此大规模的数据,无论是分析型场景、流批一体、增量数仓都得益于湖仓一体等数据湖技术…

RocketMQ文件准备

1、RocketMQ下载 下载地址:下载 | RocketMQ Source下载与Binary下载区别: binary是编译好的可以直接使用,source是还没编译过的源代码,需要自行编译。 这里大家自行下载需要的版本 2、RocketMQ管理界面 因为Rocket没有图形化管理…

渗透测试 | 信息收集常用方法总结

目录 一、关于域名 1.子域名收集 a.搜索引擎查找 b.在线查询 c.工具 d.SSL/TLS证书查询 2.端口型站点收集 3.目录文件扫描 a.目录扫描工具 b.github搜索 c.google搜索 d.在线网站 e.文件接口工具 4.旁站和C段 a.旁站查询 b.C段查询 5.网站技术架构信息 a.基础…

重磅!这本SCI期刊已解除「On hold」,另有Top期刊仍被调查中

近期小编在Master Journal List上查询期刊时偶然发现,此前被标记为「On Hold」的SCI期刊Biomass Conversion and Biorefinery,已经被科睿唯安取消了「On Hold」标识! 查询网址:https://mjl.clarivate.com/home 此前期刊处于「On …

【Petalinux】制作SD卡 操作系统 启动

Vivado 添加 SD0 导出hdf 制作SD卡 https://mathd.blog.csdn.net/article/details/135217761 【Petalinux】下为空白SD卡建立BOOT,rootfs分区 Petalinux 生成 Petalinux 框架 petalinux-create --type project --template zynq --name sdtest进入 sdtest 文件…

Python3.12 新版本之f-string的几个新特性

目录 概述 f-string表达式 1. 支持转义字符 2. 支持多行字符串 3. 支持重复使用的引号种类 4. 支持无限嵌套 附录 Python3.12新语法特性 概述 Python 3.12在10月2日发布,新版本包含一系列对语言和标准库的改变。 库的改变主要集中在清理已弃用的 API、可…

cJSON简析

文章目录 json概要cJSON数据结构 递归解析示例references json概要 json是一种文本格式的协议 对于人的可阅读性非常好 其中object和array中的value都可以嵌套 cJSON数据结构 每个节点的数据结构如下 /* cJSON Types: */ #define cJSON_Invalid (0) #define cJSON_False (…

智能监测/检测系统EasyCVR国标接入无法播放是什么原因?该如何解决?

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快,可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等,以及支持厂家私有协议与SDK接入,包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安…

减小PAPR——DFT扩频

文章目录 前言一、DFT 扩频原理二、MATLAB 仿真1、核心代码2、仿真结果①、4QAM 调制时 IFDMA、LFDMA 和 OFDMA 的 DFT 扩频技术的 PAPR 性能②、16QAM 调制时 IFDMA、LFDMA 和 OFDMA 的 DFT 扩频技术的 PAPR 性能③、64QAM 调制时 IFDMA、LFDMA 和 OFDMA 的 DFT 扩频技术的 PA…

Javaweb见解

1 web相关的概念 1.1 软件的基本架构 C/S(Client-Server)。比如我们手机上的app QQ软件 飞秋 特点:必须下载特定的客户端程序。服务端升级之后,客户端也需要随着升级。 B/S(Broswer-Server).比如京东网站,腾讯qq官方网站 特点&#xff1…