手动实现Promise

389 阅读4分钟

手动实现 Promise

请以官方文档为准

状态

Promise 有三个状态,分别为:

  • pending 初始状态
  • fulfilled 成功状态
  • rejected 失败状态 Promise 的只有在 pending 状态下,才能转更为其他状态,当状态变更后,无法再变更为其他状态。
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

function MyPromise(excutor){
    // 初始状态为 pending
	this.status = PENDING;
}

立即执行的函数

Promise 接收一个立即执行的函数(执行器:excutor),该函数接收两个回调函数,resolve(成功回调)与 reject(失败回调)。

  • resolve 成功回调,将状态改为 fulfilled,并赋予成功的值
  • reject 失败回调,将状态改为 rejected,并赋予失败的原因
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

function MyPromise(excutor){
    // 初始状态为 pending
    this.status = PENDING;
    // 成功的值
    this.value = undefined;
    // 失败的原因
    this.reason = undefined;
    // then 的回调函数集合,后面会用到
    fulfilledCallback = [];
    rejectedCallback = [];
    
    const resolve = (value) => {
        if (this.status === PENDING) {
            this.status = FULFILLED;
            this.value = value;
        }
    }

    const reject = (reason) => {
        if (this.status === PENDING) {
            this.status = REJECTED;
            this.reason = reason;
        }
    }
    
    try{
    	excutor(resolve, reject)
    }catch(err){
    	throw err;
    }
}

then 方法

new Promise((...) => {...}).then(res => {}, err => {})

then 用来处理成功或失败状态下的回调,并根据回调的值返回一个新的 Promises

  • 接收两个回调函数
    • onResolve 成功处理函数
    • onReject 失败处理函数
  • 返回一个新的 Promise
  • 当状态为 fulfilled 时,执行 onResolve,并返回一个新的 Promise,新 Promise 的结果由 onResolve 决定
  • 当状态为 rejected 时,执行 onReject,并返回一个新的 Promise,新 Promise 的结果由 onReject 决定
  • 当状态为 pending 时,将 onResolve 与 onReject 两个函数保存起来,等待状态变更后再执行对应的函数。
    • 由于状态为 pending 时,需要保存两个回调函数,所以需要新建两个数组来保存。
MyPromise.prototype.then = function(onResolve, onReject){
	// 如果用户没写 onResolve 或 onReject,就使用默认回调
    onResolve = typeof onResolve === 'undefined'?onResolve:value => value;
    onReject = typeof onReject === 'undefined'?onReject:reason => {throw reason}
    
	// 返回一个新的 Promise
    return new MyPromise((resolve, reject) => {
    	// 当状态为 fulfilled
        if(this.status === FULFILLED){
        	setTimeout(() => {
            	try{
                	// 执行 onResolve
                	const result = onResolve(this.value);
                    // onResolve 如果返回一个 Promise,那么该 Promise 将决定 then 返回的 Promise 的结果
                    if(result instanceof MyPromise){
                    	result.then(resolve, reject)
                    }else{
                    	resolve(result)
                    }
                }catch(error){
                	reject(error)
                }
            })
        }
        
        // 当状态为 rejected 时执行,与上面差不多
        if(this.status === REJECTED){
        	try{
            	// 与上面的唯一区别就是执行的函数与传值不一样
                const result = onReject(this.reason);
                if(result instanceof MyPromise){
                    result.then(resolve, reject)
                }else{
                    resolve(result)
                }
            }catch(error){
                reject(error)
            }
        }
    })
}

优化一下上面的方法,顺便实现 pending 状态下的方法。

MyPromise.prototype.then = function(onResolve, onReject){
	return new MyPromise((resolve, reject) => {
    	// 将公用重复部分提取成一个方法
    	function handleFunc(func, value){
        	try {
                const result = func(value);
                // 如果返回一个 Promise
                if (result instanceof MyPromise) {
                    result.then(resolve, reject);
                } else {
                    resolve(result)
                }
            } catch (err) {
                reject(err)
            }
        }
        
        if (this.status === FULFILLED) {
            setTimeout(() => {
                handle(onResolve, this.value)
            })
        }

        if (this.status === REJECTED) {
            setTimeout(() => {
                handle(onReject, this.reason)
            })
        }

		// 状态为 pending,将回调函数保存到前面定义的函数集合中
        if (this.status === PENDING) {
        	// 保存到 fulfilledCallback
            this.fulfilledCallback.push(value => {
                handle(onResolve, value)
            })
            // 保存到 rejectedCallback
            this.rejectedCallback.push(reason => {
                handle(onReject, reason)
            })
        }
    })
}

当状态由 pending 状态变更到其他状态后,then 的回调函数还不会被执行,需要修改执行器 excutor 的两个回调函数,resolve、reject

function MyPromise(excutor){
	// 省略一部分代码
    const resolve = (value) => {
        if (this.status === PENDING) {
            this.status = FULFILLED;
            this.value = value;
            setTimeout(() => {
            	// 状态变更后执行 then 的回调函数
                this.fulfilledCallback.forEach(fn => fn(value))
            })
        }
    }

    const reject = (reason) => {
        if (this.status === PENDING) {
            this.status = REJECTED;
            this.reason = reason;
            setTimeout(() => {
                this.rejectedCallback.forEach(fn => fn(reason))
            })
        }
    }

    try {
        excutor(resolve, reject);
    } catch (err) {
        throw err;
    }
}

reject 方法

MyPromise.reject(reason)

返回一个给定原因的失败的Promise

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

resolve 方法

MyPromise.resolve(value);

返回一个解析过 的 Promise,如果值为另一个 Promise,那么将直接返回这个 Promise。

  • 返回一个新的 Promise,注意:该 promise 的状态有可能是成功或失败。
    • 如果是普通值,那么将解析为成功状态并返回该值
    • 如果值是一个 Promise,那么状态将由这个 Promise 决定
MyPromise.resolve = function(value){
	return new MyPromise((resolve, reject) => {
    	// 如果 value 是一个 Promise,那么结果将由这个 Promise 决定
    	if(value instanceof MyPromise){
        	value.then(resolve, reject)
        }else{
        	resolve(value)
        }
    })
}

all 方法

MyPromise.all([promise1, promise2]).then(([p1, p2]) => {}, reason => {})

等待所有 promise 都成功或有一个失败后,返回一个所有 promise 的成功结果的数组或返回一个失败的原因。

  • 接收一个数组,数组的元素可以是一个 promise,也可以是一个普通值
  • 返回一个新的 promise
  • 只要有一个失败,promise.all 就会完全失败。并返回失败状态的 promise
  • 成功状态下,存入多少个 Promise 就返回多少个成功的结果,并且结果的位置与传入 Promise 的位置相同
MyPromise.all = function (promises) {
    let results = new Array(promises.length);
    let fulfilledCount = 0;
    return new MyPromise((resolve, reject) => {
        // 如果传入的promise数组为空数组,返回一个带空数组结果的成功的 promise
        if (promises.length === 0) {
            resolve([])
        }

        // 处理成功的返回
        function fulfilledHandle(value, index) {
            fulfilledCount++;
            results[index] = value;
            if (fulfilledCount === promises.length) {
                resolve(results)
            }
        }
        promises.forEach((promise, index) => {
            // 如果数组中的元素是一个 promise
            if (promise instanceof MyPromise) {
                promise.then(res => {
                    fulfilledHandle(res, index)
                }, reason => {
                    reject(reason)
                })

                // 不是 promise,直接添加到成功的结果集
            } else {
                fulfilledHandle(res, index)
            }
        })
    })
}

race 方法

MyPromise.race([promise.resolve(1), promise.reject(2)]).then(res=>{},reason=>{})

该方法返回一个 promise,接收一个数组,一旦数组中的某个 promise 成功或失败,返回的promise就会更具这个状态决定成功或失败。

注意: 只会取第一个成功或失败的 promise 或值,其他的忽略。

MyPromise.race = function (promises) {
    return new MyPromise((resolve, reject) => {
        promises.forEach(promise => {
            if (promise instanceof MyPromise) {
                promise.then(resolve, reject)
            } else {
                resolve(promise)
            }
        })
    })
}