手写promise

作者: 姜治宇 | 来源:发表于2020-04-01 11:25 被阅读0次

    promise承诺,是es6一个非常重要的解决回调地狱的工具,其本质就是个观察者模式。其实现思路是:
    在then注册事件,通过resolve或reject触发事件。
    今天我们就试着手写一个简版的promise,对大家理解promise更有帮助。

    第一步:整体框架

    我们先搭一个promise的整体框架:

    function myPromise(callback){
        function resolve(){
            console.log('ok')
        }
        function reject(){
            console.log('error')
        }
        callback(resolve,reject)
    
    
    }
    
    let p = new myPromise(function(resolve,reject){
        setTimeout(function(){
            resolve()
        },500)
    })
    

    别小看这段代码,这里涉及到高阶函数的概念,请大家仔细咂摸一下。如果实在看不明白也不要紧,那先看个简单的:

    let convert = function(val,fn){
        //转换val值,fn是转换规则
        return fn(val)
    }
    
    let toInt = function(val){
        return parseInt(val)
    }
    let res = convert('100.2',toInt)
    console.log(res)
    

    高阶函数的高阶,就是往上走,先不执行,其实就是延迟执行

    第二步:填充属性

    框架有了,下面需要准备一些必备属性了。
    观察者模式大家想必都比较熟悉,我们起码需要一个数组,用来存放待触发的函数。
    promise需要的属性清单是:
    1、两个数组,分别存放成功和失败两种情况下待触发的函数。
    2、状态属性,因为promise有三种状态,分别是:pending、resolve和reject。
    3、成功和失败的value信息。
    好,我们再完善一下代码:

    function myPromise(callback){
        var self = this;
        self.status = 'pending'//状态位
        self.onFulfilledCallbacks = []//存放成功触发的函数
        self.onRejectedCallbacks = []//存放失败触发的函数
        self.value = null//成功的返回值
        self.reason = null//失败的返回值
        function resolve(value){
            if(self.status === 'pending'){
                self.status = 'fulfilled'
                self.value = value;
                self.onFulfilledCallbacks.forEach(fn=>fn())
    
            }
        }
        function reject(reason){
            if(self.status === 'pending'){
                self.status = 'rejected'
                self.reason = reason;
                self.onRejectedCallbacks.forEach(fn=>fn())
            }
        }
        try{
            callback(resolve,reject) //执行高阶函数
        }catch(err){
            reject(err)
        }
    }
    

    第三步:then函数

    then就是用来注册待触发的函数。

    myPromise.prototype.then = function(onFulfilled,onRejected){
        let self = this;
        if(self.status === 'pending'){
            self.onFulfilledCallbacks.push(function(){
                onFulfilled(self.value)
            })
            self.onRejectedCallbacks.push(function(){
                onRejected(self.reason)
            })
        }
    }
    

    第四步:测试一下

    function myPromise(callback){
        var self = this;
        self.status = 'pending'
        self.onFulfilledCallbacks = []
        self.onRejectedCallbacks = []
        self.value = null
        self.reason = null
        function resolve(value){
            if(self.status === 'pending'){
                self.status = 'fulfilled'
                self.value = value;
                self.onFulfilledCallbacks.forEach(fn=>fn())
    
            }
        }
        function reject(reason){
            if(self.status === 'pending'){
                self.status = 'rejected'
                self.reason = reason;
                self.onRejectedCallbacks.forEach(fn=>fn())
            }
        }
        try{
            callback(resolve,reject) //执行高阶函数
        }catch(err){
            reject(err)
        }
    }
    
    myPromise.prototype.then = function(onFulfilled,onRejected){
        let self = this;
        if(self.status === 'pending'){
            self.onFulfilledCallbacks.push(function(){
                onFulfilled(self.value)
            })
            self.onRejectedCallbacks.push(function(){
                onRejected(self.reason)
            })
        }
    }
    
    new myPromise(function(resolve,reject){
        setTimeout(function(){
            resolve({code:200,data:'ok'})
        },500)
    }).then(function(res){
        console.log(res)
    })
    

    第五步:修正

    还有点小瑕疵不知道大家注意到木有:

    new myPromise(function(resolve,reject){
    
            resolve({code:200,data:'ok'})
    
    }).then(function(res){
        console.log(res)
    })
    

    如果resolve函数是立即执行而不是延时的话,那再往缓存数组里面丢就没意义了,这种情况我们需要在then函数内部单独判断一下:

    myPromise.prototype.then = function(onFulfilled,onRejected){
        let self = this;
        if(self.status === 'pending'){
            self.onFulfilledCallbacks.push(function(){
                onFulfilled(self.value)
            })
            self.onRejectedCallbacks.push(function(){
                onRejected(self.reason)
            })
        }
        //立即执行的情况
        if(self.status==='fulfilled'){
            onFulfilled(self.value)
        }
       //立即执行的情况
        if(self.status === 'rejected'){
            onRejected(self.value)
        }
    
    }
    

    第六步:完整版

    function myPromise(callback){
        var self = this;
        self.status = 'pending'
        self.onFulfilledCallbacks = []
        self.onRejectedCallbacks = []
        self.value = null
        self.reason = null
        function resolve(value){
            if(self.status === 'pending'){
                self.status = 'fulfilled'
                self.value = value;
                self.onFulfilledCallbacks.forEach(fn=>fn())
    
            }
        }
        function reject(reason){
            if(self.status === 'pending'){
                self.status = 'rejected'
                self.reason = reason;
                self.onRejectedCallbacks.forEach(fn=>fn())
            }
        }
        try{
            callback(resolve,reject) //执行高阶函数
        }catch(err){
            reject(err)
        }
    }
    
    myPromise.prototype.then = function(onFulfilled,onRejected){
        let self = this;
        if(self.status === 'pending'){
            self.onFulfilledCallbacks.push(function(){
                onFulfilled(self.value)
            })
            self.onRejectedCallbacks.push(function(){
                onRejected(self.reason)
            })
        }
        if(self.status==='fulfilled'){
            onFulfilled(self.value)
        }
        if(self.status === 'rejected'){
            onRejected(self.value)
        }
    
    }
    
    new myPromise(function(resolve,reject){
    
            resolve({code:200,data:'ok'})
    
    }).then(function(res){
        console.log(res)
    })
    

    当然真实的promise比这复杂的多,手写的意义在于加深理解,而不是炫技,重复创造是毫无意义的。

    相关文章

      网友评论

        本文标题:手写promise

        本文链接:https://www.haomeiwen.com/subject/nahouhtx.html