ES6学习(四):promise的使用和实例方法

前言

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

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

成功的逻辑
javascript 复制代码
        //成功的promise
        let prmFn1 = new Promise((resolve,jeject)=>{
            setTimeout(()=>{
                //模拟执行一个很消耗时间的任务
                resolve('我是成功的值')
            },5000)
            
        })
        prmFn1.then(resolve=>{
            console.log(resolve)    //5秒后输出:我是成功的值
        })
失败的逻辑
javascript 复制代码
        //失败的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

定义成功后回调

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

reject

定义失败后回调

javascript 复制代码
        //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内发生意外报错回调处理

javascript 复制代码
        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

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

异步都成功

javascript 复制代码
        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, '三个都执行完毕')
        })

异步中有失败

javascript 复制代码
        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可以做到

javascript 复制代码
        //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

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

成功的情况

javascript 复制代码
        //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, '失败逻辑')

            })

失败的情况

javascript 复制代码
        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

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

javascript 复制代码
        //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任务执行成功还是失败,执行完毕后都会进入这个方法

javascript 复制代码
        //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链
javascript 复制代码
        //层层依赖形成执行链
        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)

            })
        })

效果如下

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

代码改造如下

javascript 复制代码
        //中断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

相关推荐
桃园码工8 分钟前
15_HTML5 表单属性 --[HTML5 API 学习之旅]
前端·html5·表单属性
百万蹄蹄向前冲1 小时前
2024不一样的VUE3期末考查
前端·javascript·程序员
轻口味1 小时前
【每日学点鸿蒙知识】AVCodec、SmartPerf工具、web组件加载、监听键盘的显示隐藏、Asset Store Kit
前端·华为·harmonyos
alikami1 小时前
【若依】用 post 请求传 json 格式的数据下载文件
前端·javascript·json
吃杠碰小鸡2 小时前
lodash常用函数
前端·javascript
emoji1111112 小时前
前端对页面数据进行缓存
开发语言·前端·javascript
泰伦闲鱼2 小时前
nestjs:GET REQUEST 缓存问题
服务器·前端·缓存·node.js·nestjs
m0_748250032 小时前
Web 第一次作业 初探html 使用VSCode工具开发
前端·html
一个处女座的程序猿O(∩_∩)O2 小时前
vue3 如何使用 mounted
前端·javascript·vue.js
m0_748235952 小时前
web复习(三)
前端