Promise回顾: 手写一个promise

713 阅读4分钟

题记

之前跟着课程写过一个promise,这次来实习培训,老师让我们学习promise相关的知识,我就想着上次已经把一些基本用法学的差不多了,但是原理什么的只能说有点印象,所以这次决定再写一次,看看两次下来能不能有新体会,希望能把promise原理彻底理清。

开写

首先完成了MyPromise类的构建,以及基本的异步功能。 即 new MyPromise(resolve, reject).then(value => {}, reason => {})这样的功能,诸如链式调用,Promise.all这样的特性和方法在后面完善。

/*
首先是promise的三个状态: 等待态PENDING,完成态FULFILLED, 失败态REJECTED
状态的改变是不可逆的,即只有 PENDING => FULFILLED, PENDING => REJECTED 这两种形式
*/
const PENDING = 'PENDING'
const FULFILLED  = 'RESOLVE'
const REJECTED = 'REJECT'
/*
构造一个 MyPromise 类,使用ES6的类写法
*/
class MyPromise {
	/*构造器函数接收的executor是一个函数,executor会在实例化 MyPromise 时立即执行*/
    constructor(executor) {
        try {
            executor(this.resolve.bind(this), this.reject.bind(this))
        } catch(e) {
            this.reject(e)
        }
    } 
    /*初始状态为PENDING*/
    status = PENDING
    value = undefined // promise的值,在resolve方法中获取
    reason = undefined // 失败的原因,在reject方法中获取
    successCallback = null // 成功回调函数
    failCallback = null // 失败回调函数
	
    /*执行成功的函数,此时会接收到执行成功的值value*/
    resolve(value) {
       if(this.status !== PENDING) return // 若非PENDING态,则不应执行此函数
        this.status = FULFILLED // 将状态置为完成态
        this.value = value // 保存传入的值
        this.successCallback && this.successCallback(this.value) // 执行成功回调
    }
    /*同resolve类似*/
    reject(reason) {
       if(this.status !== PENDING) return
        this.status = REJECTED
        this.reason = reason
        this.failCallback && this.failCallback(this.reason)
    }
    /*状态改变后的回调函数,可以对promise后产生的值进行后续处理*/
    then(successCallback, failCallback) {
        this.successCallback = successCallback ? successCallback: value => value
        this.failCallback = failCallback ? failCallback: reason => { throw reason }
		/*
        通过状态判断执行哪个回调函数
        */
        switch(this.status) {
            case FULFILLED: {
               this.successCallback(this.value)
            }
            case REJECTED: {
                this.failCallback(this.reason)
            }
        }
    }
}

进阶版:接下来对这个基本功能的promsie进行改进,可以接收多个回调函数,可以进行链式调用

const PENDING = 'PENDING'
const FULFILLED  = 'RESOLVE'
const REJECTED = 'REJECT'
class MyPromise {
    constructor(executor) {
        try {
            executor(this.resolve.bind(this), this.reject.bind(this))
        } catch(e) {
            this.reject(e)
        }
    } 
    status = PENDING
    value = undefined
    reason = undefined
    successCallbackQueue = [] // 将单个回调函数改变为一个回调函数数组,这样就可以接收多个回调函数了
    failCallbackQueue = []
    resolve(value) {
       if(this.status !== PENDING) return
        this.status = FULFILLED
        this.value = value
        /*
        从成功回调数组头部取出回调函数并执行
        */
       while(this.successCallbackQueue.length > 0) {
           this.successCallbackQueue.shift()(this.value)
       }
    }
    reject(reason) {
       if(this.status !== PENDING) return
        this.status = REJECTED
        this.reason = reason
        /*
        从失败回调数组头部取出回调函数并执行
        */
       while(this.successCallbackQueue.length > 0) {
           this.failCallbackQueue.shift()(this.reason)
       }
    }
    /* 
    想要链式调用,then方法必须返回一个 MyPromise 
    这个新的 MyPromise接收到的value和reason就是第一个 mypromise resolve或reject中的回调函数执行后返回的值
    */
   then(successCallback,failCallback){
    successCallback = successCallback ? successCallback:value => value	      
    failCallback = failCallback ? failCallback:reason => {throw reason}
    //通过状态判断该执行哪个回调
    let newPromise = new MyPromise((resolve,reject) =>{  
    switch(this.status) {
    case FULFILLED: {
        //异步执行,以拿到newPromise
        setTimeout(() => {
            let x = successCallback(this.value)
            this.handlePromise(x,resolve,reject) //将成功回调的值传给下个promise的then  
        },0)			
    } break
    case REJECTED: {
        //异步执行,以拿到newPromise
        setTimeout(() => {
        let x = failCallback(this.reason)
        this.handlePromise(x,resolve,reject) 
        },0)
    }break
    case PENDING: {
        // 存储成功和失败回调
        this.successCallbackQueue.push(() => {
            setTimeout(() => {
               let x = successCallback(this.value)
               this.handlePromise(x,resolve,reject) 
            },0)			
        })
        this.failCallbackQueue.push(() => {
            setTimeout(() => {
                let x = failCallback(this.reason)
                this.handlePromise(x,resolve,reject) 
            },0)
        })		
    }break
    } 
   })
  return newPromise
}
    /*回调返回值处理函数*/
    handlePromise(x, resolve, reject) {
        if(x instanceof MyPromise) { // 若x是一个 MyPromise对象,则resolve或reject他执行后then方法里的值
            x.then(value => resolve(value),reason => reject(reason))
        } else {
            resolve(x) // 若是普通类型,则直接resolve
        }
    }
}

终极版:完成了promise的基本功能后,可以为我的promsie类增加一些静态方法了,这些方法可以让我的promise更加顺手。我新增了Promise.all, Promise.race, Promise.finall 等方法

    /*
    Promise.all, 接收一个数组,会等数组里所有的promise状态改变后返回一个结果数组,但必须都是resolve,否则只会抛出第一个reject的错误
    */
    static all(promiseArray) {
        return new MyPromise((resolve, reject) => {
            let count = promiseArray.length
            const res = []
            while(promiseArray.length > 0) {
                const x = promiseArray.shift()
                /*若 数组元素x是myPromise,则调用它的then方法,并将结果push到一个数组中 */
                if(x instanceof MyPromise) {
                    x.then(value => {
                        res.push(value)
                        count--
                        if(count === 0) resolve(res)
                    }, reason => {
                        reject(reason)
                    })
                } else {
                    // 普通元素,包装成MyPromise.resolve的形式,其实直接放是一样的
                    res.push(x)
                    count--
                    if(count === 0) resolve(res)
                }
            }
        })
    }

    /*Promise.reca 和all类似都是接受一个promise数组,但是他在第一个promise状态改变后就会返回这个结果,不管是resolve还是reject*/
    static race(promiseArray) {
        return new MyPromise((resolve, reject) => {
            const res = []
            while(promiseArray.length > 0) {
                const x = promiseArray.shift()
                if(x instanceof MyPromise) {
                    x.then(value => {
                        resolve(value)
                    }, reason => {
                        reject(reason)
                    })
                }
            }
        })
    }
    static resolve(n) { // 返回一个已经resolve了的promise
        if(n instanceof MyPromise) return n
        return new MyPromise(resolve => resolve(n))
    }

    /*finally */
    finally(callback){ // 无论resolve还是reject,都会执行这个finally函数
		return this.then(value => {
			// 等待callback执行完成后返回value
			return MyPromise.resolve(callback()).then(() => value)
		},reason => {
           return  MyPromise.resolve(callback()).then(() => reason)
		})
	}