手动实现一个完整的promise是个什么感受

说到promise,学前端的应该都很熟悉了。promise的用处可谓是很大了,解决地狱回调,异步并发任务的执行...

最近感觉用promise就像用框架一下,知道一些API和基本用法,就可以使用promise做一些简单的操作。既然有框架那么就有对应的底层源码,那就深入的学习一下吧。以下仅是个人的思考的写法,参考了一些大佬的思路,如有偏颇请批评指正。

 

总而言之,手写promise确实不简单,开始写之前可以先将promise的基本用法写上做一个对照。

//promise的基本用法
const p=new Promise((resolve,reject)=>{
    resolve(2)
    //reject(1)

    // setTimeout(()=>{ //模拟异步请求
    //     console.log(1)
    // },0)
})
p.then(res=>{
    console.log(res)
},err=>{
    console.log(err)
})

首先实现一个基础版的:

  • 设置三个状态常量,PENDING,RESOLVED,REJECTED,并且维持单向改变。
  • MyPromise接受一个executor函数,有两个方法resolve和reject
  • resolve()将状态改为RESOLVED,并且让promise具有一个value
  • reject()将状态改为REJECTED,并且让promise具有一个reason
const PENDING='pending'
const RESOLVED='resolved'
const REJECTED='rejected'

function MyPromise(executer){
    //初始化状态
    this.state=PENDING
    this.value=null
    this.reason=null
    
    //定义resolve和reject方法
    const resolve=(value)=>{
        //设置promise的单向状态
        if(this.state===PENDING){
            this.state=RESOLVED
            this.value=value
        }
    }
    const reject=(reason)=>{
        //设置promise的单向状态
        if(this.state===PENDING){
            this.state=REJECTED
            this.reason=reason
        }
    }
    try{
        executer(resolve,reject)
    }catch(reason){
        reject(reason)
    }

}

 

接下来就是then方法的实现了,实例可以直接调用then,则说明,then是在构造函数原型上的

  • 接受两个函数参数,onFulfilled,onRejected,分别在promise变为RESOLVED,REJECTED执行
  • 一个promise可以绑定多个then,并且then可以链式调用
  • then方法可以同步调用也可以异步调用
MyPromise.prototype.then=function(onFulfilled,onRejected){

    //允许链式调用,返回一个promise
    return new MyPromise((resolve,reject)=>{
            //this的指向是MyPromise的实例

            //由于then里面的方法是异步执行的,
            //用setTimeout模拟
            switch (this.state) {
                case RESOLVED:
                    // onFulfilled(this.value)
                    setTimeout(()=>{
                        const x= onFulfilled(this.value)
                        resolve(x)      
                    },0)
                    break;
                case REJECTED:
                    // onRejected(this.reason)
                    setTimeout(()=>{
                        const x=onRejected(this.reason) 
                            resolve(x) 
                    },0)
                    break;
                case PENDING:
                    this.onFulfilledCallbacks.push(()=>{
                        // onFulfilled(this.value)
                        setTimeout(()=>{
                            const x= onFulfilled(this.value)
                            resolve(x)
                        },0)
                    })
                    this.onRejectedCallbacks.push(()=>{
                        // onRejected(this.reason)
                        setTimeout(()=>{
                            const x=onRejected(this.reason) 
                            resolve(x)
                        },0)
                    })
                    break;
            }
    })
}

catch和finally的实现都是建立在then的基础上的,finally无论最终promise的状态是成功还是失败

都会执行传入的函数。

//catch和finally

MyPromise.prototype.catch=function(onRejected){
    return this.then(null,onRejected)
}

MyPromise.prototype.finally=function(fn){
    return this.then(res=>{
        fn()
        return res
    },err=>{
        fn()
        throw new Error(err)
    })
}

 同理,MyPromise.resolved和MyPromise.reject也可以依据已将包装好的MyPromise来实现

//MyPromise.resolved和MyPromise.reject
MyPromise.resolve=function(value){
    return new MyPromise(resolve=>{
        resolve(value)
    })
}

MyPromise.reject=function(reason){
    return new MyPromise((resolve,reject)=>{
        reject(reason)
    })
}

最后就剩下MyPromise的all,race,any,allsettled方法,注意这些方法就不在MyPromise的原型对象上,而是直接在MyPromise上

 


//MyPromise的all,race,any,allsettled
//all
MyPromise.all=function(promises){
    return new MyPromise((resolve,reject)=>{
        if(promises.length==0){
            return resolve([])
        }
        let results=[]
        let length=promises.length
        for(let i=0;i<length;i++){
            promises[i].then(res=>{
                if(++i==length){
                    resolve(results)
                }
                results[i]=res
            }).catch(err=>{
                reject(err)
                return
            })
        }
    })
}

//race
MyPromise.race=function(promises){
    return new MyPromise((resolve,reject)=>{
        for(let i=0;i<promises.length;i++){
            promises[i].then(res=>{
                resolve(res)
                return
            }).catch(err=>{
                reject(err)
                return
            })
        }
    })
}

//any
MyPromise.any=function(promises){
    return new MyPromise((resolve,reject)=>{
        let results=[]
        let length=promises.length
        for(let i=0;i<length;i++){
            promises[i].then(res=>{
                resolve(res)
                return
            }).catch(err=>{
                results[i]=err
                if(++i==length){
                    reject(results)
                }
            })
        }
    })
}

//allSettled
MyPromise.allsettled=function(promises){
    return new MyPromise((resolve,reject)=>{
        let results=[]
        for(let i=0;i<promises.length;i++){
            promises[i].then(res=>{
                results[i]=res
            }).catch(err=>{
                results[i]=err
            }).finally(()=>{
                if(++i==promises.length){
                    resolve(results)
                }
            })
        }
    })
}

至此promise里面的常用的API基本已经实现了,总结一下就是,后面四个API里面的代码逻辑差不多,具体到resolve和reject的不同依据不同的期待返回值来定。如果有哪里不正确或者可以优化的地方,欢迎交流探讨!

每天都要进步一点点!加油!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值