Promise从入门到放弃

Promise

1、介绍

1.1、Promise是什么

Promise是ES6中提出的JavaScript中进行异步编程的一种新的解决方案(旧方案就是使用回调函数)

从语法上来说,就是一个构造函数

从功能上来说,Promise可以封装一个异步操作并过去其成功或失败的结果

1.2、为什么要使用Promise

指定回调函数的方式更加灵活

支持链式调用,能够解决回调地狱的问题

2、Promise使用

2.1 promise的三种状态

  • pending,初始化状态
  • fulfilled/resolved,成功状态
  • rejected,失败状态

当我们创建一个Promise实例时,该实例的状态为pending,promise的状态只能从pending切换到fulfilled或从pending切换到rejected,且只能切换一次

2.2 如何使用

promise本质上是一个构造函数,所以我们可以通过new关键字来进行使用

promise接收一个回调函数(可以是箭头函数或匿名函数),该回调函数称为执行器函数,在Promise内部同步调用

const p = new Promise(()=>{
    console.log("hello Promise")
})

执行器函数传入resolve和reject两个参数,这两个参数是两个函数,可以用来修改promise实例的状态

resolve:将promise实例的状态从pending变成fulfilled

reject:将promise实例的状态从pending变成rejected

除了以上两种方法,还可以通过throw直接抛出错误的方法,将promise的状态修改为失败

const p = new Promise((resolve, reject) => {
    const randNum = Math.floor(Math.random() * 10)
    if (randNum > 5) {
        /*修改promise实例的状态为成功*/
        resolve(`success,value=${randNum}`)
    } else {
        /*修改promise实例的状态为失败*/
        reject(`error,value=${randNum}`)
    }
})
console.log(p)

2.3 then() 方法

then方法是promise原型对象上的方法,最多接收两个函数,第一个为promise状态为fulfilled的回调函数,第二个为promise状态为rejected的回调函数

const p = new Promise((resolve, reject) => {
    const randNum = Math.floor(Math.random() * 10)
    /*通过随机数随机修改promise的状态*/
    if (randNum > 5) {
        /*修改promise实例的状态为成功*/
        resolve(`success,value=${randNum}`)
    } else {
        /*修改promise实例的状态为失败*/
        reject(`error,value=${randNum}`)
    }
})
p.then(success => {
    console.log(success)
},error => {
    console.log(error)
})

then方法最终返回一个新的promise,该promise对象的状态和结果均由then方法指定的回调函数的执行结果决定

  • 如果回调函数返回一个新的promise,则此promise的结果和状态就会成为then方法返回的promise的结果和状态
  • 如果返回的是一个非promise值,结果为这个值,状态为成功(不论是成功回调还是失败回调),如果回调函数没有写返回值,则返回undefined
  • 如果抛出错误,新promise的状态为失败,结果为抛出的错误

由于then方法返回一个新的Promise对象,所以支持链式调用

const p = new Promise((resolve, reject) => {
    resolve(1)
})
const result = p.then(value => {
    console.log(value)
    return value
}).then(value => {
    console.log(value)
    return value
})
result.then(value => {
    console.log(value)
    return value
})

如果希望中断Promise的链式调用,有且只有一种方法:返回一个pending状态的promise对象

const p = new Promise((resolve, reject) => {
    resolve(111)
})
 p.then(value => {
    console.log(222)
    return new Promise(()=>{})
}).then(value => {
    console.log(333)
    return value
})

2.4 catch() 方法

catch方法是promise原型对象上的方法,接收一个回调函数,并在promise状态为失败时进行调用

const p = new Promise((resolve, reject) => {
    const randNum = Math.floor(Math.random() * 10)
    /*通过随机数随机修改promise的状态*/
    if (randNum > 5) {
        /*修改promise实例的状态为成功*/
        resolve(`success,value=${randNum}`)
    } else {
        /*修改promise实例的状态为失败*/
        reject(`error,value=${randNum}`)
    }
})
p.then(success => {
    console.log(success)
}).catch(error => {
    console.log(error)
})

**异常穿透:**当我们链式调用then方法时,不必每次都写错误处理函数,只需在最后加上一个.cath方法,即可完成整个调用的错误捕获

const p = new Promise((resolve, reject) => {
    reject("error")
})
p.then(value => {
    console.log(222)
    return value
}).then(value => {
    console.log(333)
    return value
}).catch(error => {
    console.log(error)
})

3、Promise方法

3.1 resolve()

Promise.resolve()方法直接返回一个Promise对象

resolve可以接收一个参数,如果该参数是一个非Promise类型的对象,则返回一个状态为成功的Promise对象

如果该参数是一个Promise类型的对象,则resolve方法放回的Promise对象的状态取决于参数Promise对象的状态

const p1 = Promise.resolve(null)
// 通过resolve创建了一个promise对象,该对象的状态为成功
console.log(p1)

const p2 = Promise.resolve(new Promise((resolve, reject)=>{reject("error")}))
// resolve接受了一个失败状态的promise,所以resolve方法返回的promise对象的状态也是失败
console.log(p2)

3.2 reject()

Promise.reject()方法直接返回一个Promise对象

reject可以接收一个参数,作为promise的结果

该对象的状态一定为失败

3.3 all()

Promise.all()方法接收一个由promise组成的数组,并返回一个Promise

当数组中所有的Promise为成功时,返回一个成功状态的Promise对象,成功的结果就是每一个Promise对象结果组成的一个数组

当数组中有一个Promise为失败时,返回一个失败状态的Promise对象,不论多少个失败的Promise对象,all方法失败的结果就是数组中第一个失败的这个Promise失败的结果

const promiseList1 = [
    Promise.reject(1),
    Promise.resolve(2),
    Promise.resolve(3),
]
const p1 = Promise.all(promiseList1)
console.log(p1)

const promiseList2 = [
    Promise.reject(1),
    Promise.reject(2),
    Promise.resolve(3),
]

const p2 = Promise.all(promiseList2)
console.log(p2)

3.4、race()方法

Promise.race()方法接收一个由Promise组成的数组,并返回一个Promise

返回的promise的状态和结果取决于数组中第一个状态发生修改的Promise

// 定义一个获得0-999随机数的方法,用于随机生成定时器的时间
const randomSleepTime = () => Math.floor(Math.random() * 1000)
// 这是一个promise列表
const promiseList = [
    // 定义了一个一定成功的promise,状态在随机时间后发生修改
    new Promise(resolve => {
        setTimeout(()=>resolve("success"),randomSleepTime())
    }),
    // 定义了一个一定失败的promise,状态在随机时间后发生修改
    new Promise((resolve,reject) => {
        setTimeout(()=>reject("success"),randomSleepTime())
    })
]
const p = Promise.race(promiseList)
console.log(p)

4、手写Promise

/**
 * @author 太阳当空丶赵
 * @date 2022/11/20-22:53
 * @version 1.0.0
 * 手写promise——class版本
 */
/*定义promise状态*/
const stateMenu = {
    PENDING: "pending",
    RESOLVED: "fulfilled",
    REJECTED: "rejected"
}

class MyPromise {
    /*设置初始状态为pending*/
    promiseState = stateMenu.PENDING
    /*初始结果为null*/
    promiseResult = null
    /*使用一个列表来存储异步方法的回调函数*/
    callBackList = []

    constructor(executor) {
        /*
        * 解决类方法中的this指向问题
        * 这里的resolve和reject是通过类调用,this不指向实例
        * then方法是作为实例的原型方法进行调用,this指向原型
        * 除了通过bind修改函数上下文,还可以使用箭头函数
        * */
        this.resolve = this.resolve.bind(this)
        this.reject = this.reject.bind(this)

        /*执行器函数调用,使用try/catch捕获异常,发生异常时直接将promise状态设置为失败*/
        try {
            executor(this.resolve, this.reject)
        } catch (e) {
            this.reject(e)
        }
    }

    resolve(data) {
        /*如果状态已经被修改,则不做任何操作,确保状态只能被修改一次*/
        if (this.promiseState !== stateMenu.PENDING) return null
        // 将状态修改为成功
        this.promiseState = stateMenu.RESOLVED
        // 保存成功的数据
        this.promiseResult = data
        /*
        * 很多时候,promise中执行的并不是同步代码,修改状态的操作可能在then方法执行之后
        * 这里是将then方法中保存的回调列表进行遍历,同时执行所有成功的回调
        * 为什么是一个回调列表?
        * 因为可能不只有一个then方法,
        * 所以需要将所有then方法的回调都存到实例上
        * */
        for (const callBack of this.callBackList) {
            callBack.onResolved()
        }
    }

    reject(data) {
        if (this.promiseState !== stateMenu.PENDING) return null
        this.promiseState = stateMenu.REJECTED
        this.promiseResult = data
        /*与resolve相同,只不过这里调用的是失败的回调*/
        for (const callBack of this.callBackList) {
            callBack.onRejected()
        }

    }

    /*then方法可以接收两个回调函数,第一个是成功的回调函数,第二个是失败的回调*/
    then(onResolved, onRejected) {
        const that = this
        /*当不传递错误处理的回调方法时,默认抛出错误,这里是catch能够在链式调用中捕获错误的关键*/
        if (typeof onRejected !== "function") {
            onRejected = function () {
                throw that.promiseResult
            }
        }
        /*当不传入成功处理回调时,默认传入下一次调用,也就是将成功的结果存放到新的promise中*/
        if (typeof onResolved !== "function") {
            onResolved = value => value
        }

        /*then方法返回一个promise对象*/
        return new MyPromise((resolve, reject) => {

            /*不同状态的处理函数*/
            function stateHandler(type) {
                try {
                    // 获取回调函数的执行结果
                    const result = type(that.promiseResult)
                    // 如果结果是一个promise,那么then方法返回的这个promise的结果由返回的promise决定
                    if (result instanceof MyPromise) {
                        result.then(v => {
                            resolve(v)
                        }, r => {
                            reject(r)
                        })
                    // 如果结果不是一个promise,直接返回一个成功状态的promise
                    } else {
                        resolve(result)
                    }
                } catch (e) {
                    // 异常捕获
                    reject(e)
                }
            }

            // 当promise状态为成功时,调用成功的回调,用于同步情况
            if (that.promiseState === stateMenu.RESOLVED) {
                stateHandler(onResolved)
            }
            // 当promise状态为失败时,调用失败的回调,用于同步情况
            if (that.promiseState === stateMenu.REJECTED) {
                stateHandler(onRejected)
            }
            /*
            * 当promise的执行器函数是一个异步方法,
            * 在调用then方法时,promise的状态可能还未发生改变,需要在状态发生改变时调用对应的回调函数
            * */
            if (that.promiseState === stateMenu.PENDING) {
                /*
                * 将对应的回调函数保存到实例自身,方便在实例状态发生改变的情况调用
                * 什么时候发生变化?
                * 调用resolve、reject或抛出错误时
                * */
                that.callBackList.push({
                    onResolved: () => {
                        stateHandler(onResolved)
                    },
                    onRejected: () => {
                        stateHandler(onRejected)
                    }
                })
            }
        })
    }

    /*
    * catch方法用于捕获promise中发生的错误,
    * 其原理就是对then方法的封装,
    * 直接返回then方法,同时传入错误处理的回调
    * */
    catch(onRejected) {
        return this.then(undefined, onRejected)
    }

    /*静态方法,通过类直接调用*/
    static resolve(data) {
        /*
        * resolve方法接收一个参数,同时返回一个promise
        * */
        return new MyPromise((resolve, reject) => {
            if (data instanceof MyPromise) {
                // 如果是promise,直接调用该promise的then方法并将成功或失败的结果作为返回的promise的结果
                data.then(v => resolve(v), r => reject(r))
            } else {
                // 如果参数是一个非promise值,则返回一个成功状态的promise
                resolve(data)
            }
        })
    }

    static reject(data) {
        /*reject方法直接返回一个失败状态的promise*/
        return new MyPromise((resolve, reject) => {
            reject(data)
        })
    }

    static all(promiseList) {
        /*
        * all方法接收一个promise列表
        * */
        return new MyPromise((resolve, reject) => {
            // 定义一个变量用于保存成功的promise的数量
            let successNum = 0
            let resultList = []
            /*通过索引确保每一个promise的结果按照顺序存放到结果数组中,因为任务中可能存在异步任务,直接使用push方法可能导致顺序错乱*/
            for (let i = 0; i < promiseList.length; i++) {
                promiseList[i].then(result => {
                    // 如果当前的promise执行成功,则将成功的结果保存到数组里,同时成功数量+1
                    resultList[i] = result
                    successNum++
                    // 当成功的数量与promise数组长度相同时,说明所有promise均执行成功,调用resolve方法
                    if (successNum === promiseList.length){
                        resolve(resultList)
                    }
                },reason => {
                    // 当有一个promise执行失败时,all方法返回的promise也为失败
                    reject(reason)
                })
            }
        })
    }

    static race(promiseList) {
        /*race方法接收一个promise列表,并返回第一个成功或失败的promise的结果*/
        return new MyPromise((resolve,reject) => {
            for (const promise of promiseList) {
                promise.then(result => resolve(result),reason => reject(reason))

            }
        })
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

太阳当空丶赵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值