web前端

手写promise

2020-04-01  本文已影响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比这复杂的多,手写的意义在于加深理解,而不是炫技,重复创造是毫无意义的。

上一篇 下一篇

猜你喜欢

热点阅读