手撕Promise代码

我的思路是根据这个Promise的使用方法,一步步用js还原其原理

// 这个回调函数传进来就开始执行了
let oP = new Promise((resolve, reject) => {
    resolve(1)
})

// 这个要根据你的状态进行选择 Fulfilled pending Rejected
oP.then((res) => {
    console.log(res)
}, (rej)=> {
    console.log(rej)
})
// 源码实现
// Fulfilled pending Rejected
function MyPromise(executor) {
    let self = this
    this.status = 'pending'
    this.resolveValue = null
    this.rejectValue = null
    this.ResolveCallBackList = []
    this.RejectCallBackList = []

    function resolve(val) {
       if(self.status === 'pending') {
			self.status = 'Fulfilled'
        	self.resolveValue = val
       }
    }
    function reject(reason) {
       if(self.status === 'pending') {
			self.status = 'Rejected'
            self.rejectValue = reason      
       }
    }

    try {
        executor(resolve, reject)
    } catch(e) {
        reject(e)
    }
}

MyPromise.prototype.then = function(onFulfilled, onRejected) {
    let self = this
    if(this.status === 'Fulfilled') {
        onFulfilled(self.resolveValue)
    }
    if(this.status === 'Rejected') {
        onRejected(self.rejectValue)
    }
}

现在有了初步的实现,我们继续完善功能,如果是出现如下情况

let oP = new MyPromise((resolve, reject) => {
	// resolve函数放在了异步事件中,那么此时then函数会先于resolve执行
	// then函数无法拿到resolve函数所传的值
	setTimeout(() => {
	      resolve(1)
	  });
})

解决方法:构造函数定义一个回调列表,分别对应
Fulfilled Rejected 这个状态

// Fulfilled pending Rejected
function MyPromise(executor) {
    let self = this
    this.status = 'pending'
    this.resolveValue = null
    this.rejectValue = null
    this.ResolveCallBackList = []
    this.RejectCallBackList = []

    function resolve(val) {
        if (self.status === 'pending') {
            self.status = 'Fulfilled'
            self.resolveValue = val
            self.ResolveCallBackList.forEach(item => {
                item()
            })
        }
    }
    function reject(reason) {
        if (self.status === 'pending') {
            self.status = 'Rejected'
            self.rejectValue = reason
            self.RejectCallBackList.forEach(item => {
                item()
            })
        }
    }

    try {
        executor(resolve, reject)
    } catch (e) {
        reject(e)
    }
}

MyPromise.prototype.then = function (onFulfilled, onRejected) {
    let self = this
    if (this.status === 'Fulfilled') {
        onFulfilled(self.resolveValue)
    }
    if (this.status === 'Rejected') {
        onRejected(self.rejectValue)
    }
    if (this.status === 'pending') {
        self.ResolveCallBackList.push(function () {
            onFulfilled(self.resolveValue)
        })
        self.RejectCallBackList.push(function () {
            onRejected(self.rejectValue)
        })
    }
}

继续添加功能:

功能1:由于then函数是一个微任务事件,这里我们使用setTimeout进行模拟
功能2:实现then函数的一个链式调用
功能3:then函数中出异常,利用try、catch进行处理
功能四:如果是then函数传入的参数出现空值,那么需要对参数进行非空判断并且进行重写

// Fulfilled pending Rejected
function MyPromise(executor) {
    let self = this
    this.status = 'pending'
    this.resolveValue = null
    this.rejectValue = null
    this.ResolveCallBackList = []
    this.RejectCallBackList = []

    function resolve(val) {
        if (self.status === 'pending') {
            self.status = 'Fulfilled'
            self.resolveValue = val
            self.ResolveCallBackList.forEach(item => {
                item()
            })
        }
    }
    function reject(reason) {
        if (self.status === 'pending') {
            self.status = 'Rejected'
            self.rejectValue = reason
            self.RejectCallBackList.forEach(item => {
                item()
            })
        }
    }

    try {
        executor(resolve, reject)
    } catch (e) {
        reject(e)
    }
}

MyPromise.prototype.then = function (onFulfilled, onRejected) {
    if(!onFulfilled) {
        onFulfilled = function(val) {
            return val
        }
    }
    if(!onRejected) {
        onRejected = function(reason) {
            return reason
        }
    }
    let self = this
    let nextPromise = new MyPromise(function (res, rej) {
        if (self.status === 'Fulfilled') {
            setTimeout(() => {
                try {
                    let returnValue = onFulfilled(self.resolveValue)
                    res(returnValue)
                } catch (e) {
                    rej(e)
                }
            })
        }
        if (self.status === 'Rejected') {
            setTimeout(() => {
                try {
                    let returnValue = onRejected(self.rejectValue)
                    rej(returnValue)
                } catch (e) {
                    rej(e)
                }
            })
        }
        if (self.status === 'pending') {
            self.ResolveCallBackList.push(function () {
                setTimeout(() => {
                    try {
                        let returnValue = onFulfilled(self.resolveValue)
                        res(returnValue)
                    } catch (e) {
                        rej(e)
                    }
                })                
            })
           
            self.RejectCallBackList.push(function () {
                setTimeout(() => {
                    try {
                        let returnValue = onRejected(self.rejectValue)
                        rej(returnValue)
                    } catch (e) {
                        rej(e)
                    }
                })                
            })
        }
    })
    return nextPromise
}

最后一个功能:then函数中的参数(参数是个函数)返回的是一个MyPromise对象,我们应该如何处理。案例如下:

let oP = new Promise((resolve, reject) => {
  	resolve(1)
 })
 // 这里有两个promise之间的关系问题,实际上也是我们需要解决的问题
 oP.then((res) => {
     console.log(res)
     return new Promise((res, rej) => {
         res(1) // 这个返回来的Promise对象最后赋值给then函数的内部变量
     })
 }).then(res => {
     console.log('then: ', res)
 }) 

解决方法:

// Fulfilled pending Rejected
function MyPromise(executor) {
    let self = this
    this.status = 'pending'
    this.resolveValue = null
    this.rejectValue = null
    this.ResolveCallBackList = []
    this.RejectCallBackList = []

    function resolve(val) {
        if (self.status === 'pending') {
            self.status = 'Fulfilled'
            self.resolveValue = val
            self.ResolveCallBackList.forEach(item => {
                item()
            })
        }
    }
    function reject(reason) {
        if (self.status === 'pending') {
            self.status = 'Rejected'
            self.rejectValue = reason
            self.RejectCallBackList.forEach(item => {
                item()
            })
        }
    }

    try {
        executor(resolve, reject)
    } catch (e) {
        reject(e)
    }
}

function ResolutionReturnPromise(returnValue, res, rej) {
    if(returnValue instanceof MyPromise) {
        returnValue.then((val) => {
            res(val)
        }, (reason) => {
            rej(reason)
        })
    } else {
        res(returnValue)
    }
}

MyPromise.prototype.then = function (onFulfilled, onRejected) {
    if(!onFulfilled) {
        onFulfilled = function(val) {
            return val
        }
    }
    if(!onRejected) {
        onRejected = function(reason) {
            return reason
        }
    }
    let self = this
    let nextPromise = new MyPromise(function (res, rej) {
        if (self.status === 'Fulfilled') {
            setTimeout(() => {
                try {
                    let returnValue = onFulfilled(self.resolveValue)
                
                    ResolutionReturnPromise(returnValue, res, rej)
                } catch (e) {
                    rej(e)
                }
            })
        }
        if (self.status === 'Rejected') {
            setTimeout(() => {
                try {
                    let returnValue = onRejected(self.rejectValue)
                    ResolutionReturnPromise(returnValue, res, rej)
                } catch (e) {
                    rej(e)
                }
            })
        }
        if (self.status === 'pending') {
            self.ResolveCallBackList.push(function () {
                setTimeout(() => {
                    try {
                        let returnValue = onFulfilled(self.resolveValue)
                        ResolutionReturnPromise(returnValue, res, rej)
                    } catch (e) {
                        rej(e)
                    }
                })                
            })
           
            self.RejectCallBackList.push(function () {
                setTimeout(() => {
                    try {
                        let returnValue = onRejected(self.rejectValue)
                        ResolutionReturnPromise(returnValue, res, rej)
                    } catch (e) {
                        rej(e)
                    }
                })                
            })
        }
    })
    return nextPromise
}

这里是个初稿,太困了,后续再附上详细说明和修正

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章