阅读 660

Promise:手撕Promise

什么是Promise

Promise对象是JavaScript异步操作解决方案,为异步操作提供统一接口。Promise可以让异步操作写起来,就像在写同步操作的流程,而不必一层层的嵌套回调函数。就是我们所说的回调地狱。

怎么实现一个Promise?

第一部分

实现之前我们先了解下它的一些特点,结合这些特点我们实现起来会比较容易理解一点。

  1. 有三种状态,默认是pending,成功为fulfilled,失败为rejected
  2. 创建时必须传递一个函数,不然会报错
  3. 传递函数中参数是两个回调函数,resolve和reject
  4. 状态一旦发生改变就不会发生变化

特点很多我们先按照这些特点慢慢实现

class MyPromise{
    constructor(fn) {
        // 2:promise接收的必须是个函数,不然报错
        if (!this.isFunc(fn)){
            throw new Error('这不是个函数')
        }
        // 1:定义默认状态
        this.status = 'pending'

        //3:函数参数中有两个回调参数;resolve和reject
        this.resolve = (data) =>{
            //状态一旦发生改变就不会在改变,所以在这里判断下是否为默认状态
            if (this.status === 'pending'){
                this.status = 'fulfilled'
            }
        }

        this.reject = (data) =>{
            if (this.status === 'pending'){
                this.status = 'rejected'
            }
        }
        fn(this.resolve,this.reject)
    }
    // 首先定义个方法判断是否为函数
    isFunc(fn){
        return typeof fn === 'function'
    }
}
let a = new MyPromise(function (resolve,reject){
    resolve()
    console.log('执行了');
})
console.log(a);
复制代码

看下执行结果,状态已经是成功了

第二部分

再说说还有的特点

  1. 同一个promise对象可以添加多个then监听,状态改变时会按照监听顺序依次执行
  2. then方法每次执行完毕会返回一个新的promise对象
  3. 上一个Promise对象的then方法可以给返回的新的Promise的then传递参数
  4. 无论上一个是在then成功或者失败的回调中传参,都会传递给新的Promise对象then方法中成功的回调
  5. 如果上一个传递的是一个Promise对象,那么传给下一个的成功还是失败由传递的Promsie状态决定  

代码块有点问题,放个图片

看下运行结果:

这里难理解的可能就是对then return的值进行判断,因为下个promise会继承上一个promise的状态,因为如果then中return的是一个promise对象的话,下一个promise的状态就是按照这个return过来的。

第三部分

最后一点了。也是上面的基础上的补充

  1.   then返回的promise可以捕捉当前then方法中的异常

  2. catch方法就是then方法的语法糖

多余的注释我就先去掉了,下面就是完整版的了

class MyPromise{
    constructor(fn) {
        if (!this.isFunc(fn)){
            throw new Error('这不是个函数')
        }
        this.status = 'pending'
        //定义两个属性保存resolve和reject中的参数
        this.value = undefined
        // 存放成功的数组
        this.onSuccessCallbacks = []
        this.fail = undefined
        // 存放失败的数组
        this.onFailCallbacks = []
        //函数参数中有两个回调参数;resolve和reject
        this.resolve = (data) =>{
            //状态一旦发生改变就不会在改变,所以在这里判断下是否为默认状态
            if (this.status === 'pending'){
                this.status = 'fulfilled'
                this.value = data
                if (this.onSuccessCallbacks){
                    this.onSuccessCallbacks.forEach((fn) => {
                        fn(this.value)
                    })
                }
            }
        }
        this.reject = (data) =>{
            if (this.status === 'pending'){
                this.status = 'rejected'
                this.fail = data
                if (this.onFailCallbacks){
                    this.onFailCallbacks.forEach((fn) => {
                        fn(this.fail)
                    })
                }
            }
        }
        fn(this.resolve,this.reject)
    }
    then(onSuccess,onFail){
        return new MyPromise((nextSuccess,nextFail) => {
            //then返回的promise可以捕捉当前then方法中的异常
            // 所以我们可以利用try catch来捕获异常
            try {
                if (this.isFunc(onSuccess)){
                    if (this.status === 'fulfilled'){
                        let res = onSuccess(this.value)
                        if (res instanceof MyPromise){
                            res.then(nextSuccess,nextFail)
                        }else if (res !== undefined){
                            nextSuccess(res)
                        }else {
                            nextSuccess()
                        }
                    }
                }
                // 将异常信息传递给下一个promise失败的回调
            }catch (e) {
                nextFail(e)
            }
            try {
                if (this.isFunc(onFail)){
                    if (this.status === 'rejected'){
                        let res = onFail(this.fail)
                        if (res instanceof MyPromise){
                            res.then(nextSuccess,nextFail)
                        }else if (res !== undefined){
                            nextSuccess(res)
                        }else {
                            nextFail()
                        }
                    }
                    //这里要加个判断,因为我们有时写的话可能会省略then中失败的回调,利用catch捕获
                }else if (onFail === undefined){
                    if (this.fail){
                        nextFail(this.fail)
                    }
                }
            }catch (e) {
                nextFail(e)
            }
            // 解决延迟回调的问题
            if (this.status === "pending"){
                if (this.isFunc(onSuccess)){
                    this.onSuccessCallbacks.push(() => {
                        try {
                            let res = onSuccess(this.value)
                            if (res instanceof MyPromise){
                                res.then(nextSuccess,nextFail)
                            }else if (res !== undefined){
                                nextSuccess(res)
                            }else {
                                nextSuccess()
                            }
                        }catch (e) {
                            nextFail(e)
                        }
                    })
                }
                if (this.isFunc(onFail)){
                    this.onFailCallbacks.push(() => {
                        try {
                            let res = onFail(this.fail)
                            if (res instanceof MyPromise){
                                res.then(nextSuccess,nextFail)
                            }else if (res !== undefined){
                                nextSuccess(res)
                            }else {
                                nextFail()
                            }
                        }catch (e) {
                            nextFail(e)
                        }
                    })
                }else if (onFail === undefined){
                    this.onFailCallbacks.push(nextFail)
                }
            }
        })
    }
    // catch可以看作是then的一个语法糖
    catch(onFail){
        return this.then(undefined , onFail)
    }
    // 首先定义个方法判断是否为函数
    isFunc(fn){
        return typeof fn === 'function'
    }
}
let a = new MyPromise(function (resolve,reject){
    resolve('xyz')
    // reject('xyz')
    console.log('执行了');
})
let b = a.then(function (data) {
    console.log(data,'成功');
    xxx
})
b.then(function (data) {
    console.log(data);
},function (data) {
    console.log(data,'sss');
})
复制代码

  看下执行结果

这里下一个promise成功捕捉到了上一个then中的错误

Promise的其他方法

all方法

Promise的all方法接收一个数组,数组中存放promise对象,只有数组中的promise都成功了才会执行then方法,并且会按照添加的顺序,将所有成功的结果重新打包到一个数组中返回给我们,如果有一个失败就会立即执行失败的回调。

要么一起成功,要么一起失败

//因为all是一个静态方法
static all(list){
    //因为返回的是一个数组,所以先定义一个
    let arr = []
    return new MyPromise((resolve,reject) => {
        list.forEach((value) => {
            value.then((data) => {
                arr.push(data)
            },(error) =>{
                reject(error)
            })
        })
        resolve(arr)
    })
}
复制代码

  

race方法

Promise的race方法接收一个数组,数组中存放promise对象。不过它取决于数组中第一个promise的状态

// race 也是个静态方法
static race(list){
    return new MyPromise((resolve,reject)=>{
        list.forEach((value) => {
            value.then(function (data) {
                resolve(data)
            },function (error) {
                reject(error)
            })
        })
    })
}
复制代码

总结

我表达的可能不是太好,不太容易理解,也可能有错误的地方我没检查出来。希望大家多多包含😊

文章分类
前端
文章标签