promise的使用和实例方法

news/2024/7/11 1:05:42 标签: es6, 前端

前言

异步,是任何编程都无法回避的话题。在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.niftyadmin.cn/n/5287632.html

相关文章

Flamingo与亚马逊云科技合作,进一步优化海外客户的访问体验

据中国海关统计,2023年上半年,我国跨境电商进出口规模约1.1万亿元,比上年同期(下同)增长16.6%,增速加快13.7个百分点。其中,出口约8254亿元,增长20.6%,占同期我国出口总值…

数字 IC 设计职位经典笔/面试题,建议收藏!

共100道经典笔试、面试题目(文末可全领) 什么是同步逻辑和异步逻辑? 同步逻辑是时钟之间有固定的因果关系。异步逻辑是各时钟之间没有固定的因果关系。同步时序逻辑电路的特点:各触发器的时钟端全部连接在一起,并接在…

python 读取pdf中的文本

摘要 常常需要针对pdf进行文本分析,以下给出了两种方法用来读取pdf中的文字 方法一 pypdf2 pip install PyPDF2 import PyPDF2 filename xxx.pdfwith open(filename, rb) as file:# 创建一个PDF阅读器对象reader PyPDF2.PdfReader(file)# 遍历PDF中的每一页fo…

Linux shell查看各文件夹容量大小

Linux 操作系统是一种免费的操作系统,作为开源系统,它被广泛地应用在服务器端以及部分人士的电脑操作系统上。Linux 的文件操作类似于 Windows,但是又有其独特的功能。在本篇文章中,我们将详细探讨怎样在 Linux 系统中查看各个文件…

HarmonyOS4.0系统性深入开发04UIAbility组件详解(下)

UIAbility组件间交互(设备内) UIAbility是系统调度的最小单元。在设备内的功能模块之间跳转时,会涉及到启动特定的UIAbility,该UIAbility可以是应用内的其他UIAbility,也可以是其他应用的UIAbility(例如启…

Redis案例实战之Bitmap、Hyperloglog、GEO

👏作者简介:大家好,我是爱吃芝士的土豆倪,24届校招生Java选手,很高兴认识大家📕系列专栏:Spring源码、JUC源码、Kafka原理、分布式技术原理、数据库技术🔥如果感觉博主的文章还不错的…

Java内部类介绍和使用

2 内部类 2.1 内部类的分类 什么时候使用内部类 ? 多个事物之间有包含关系, 可以使用内部类 内部类分类 ? 成员内部类局部内部类匿名内部类 2.2 成员内部类 定义的位置 : 类中方法外 创建成员内部类对象格式 : 外部类名.内部类名 对象名 new 外部类名().new 内部类名(参…

『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