高级开发者必须掌握的手写Promise(一)

607 阅读4分钟

1、概述

前两篇 Promise A+ 规范之基本介绍 Promise A+规范之Promise解决过程 详细讲解了Promise A+规范之后,我们就可以根据规范实现自己的Promise了,如果对规范记得不是很清楚,建议边看规范边写自己的Promise库~

回忆下规范,一个Promise应该有哪些基本的功能?

  • 具有三个状态
  • 状态的扭转
  • 执行(resolve)成功的value
  • 执行(reject)失败的reason
  • 注册了两个回调函数resolve和reject,用于接收 promise 的终值或本 promise 不能执行的原因,分别将状态从pending扭转为resolved和rejected,并设置value和reason
  • 具有then方法
  • then方法也要返回一个Promise实例
promise.then(onFulfilled, onRejected)

以上大概可以猜到一个Promise可以用对象来实现~

2、实现一个简单的Promise

先看下Promise提供的功能,我们照着实现相同的功能~

let promise1 = new Promise((resolve, reject) => {
    resolve('resolve: lls value is OK~');
    //reject('reject: lls reason is Fail~');
    //throw new Error('Sorry lls is Error~')
});

promise1.then(value => {
    console.log(`onFulfilled:`, value);
}, (reason) => {
    console.log(`onRejected:`, reason);
});
//分别打印出
//onFulfilled: resolve: lls value is OK~
//onRejected: reject: lls reason is Fail~
//onRejected: Error: Sorry lls is Error~

具体实现如下

//状态枚举
const STATUS = {
    PENDING: 'PENDING',
    FULFILLED: 'FULFILLED',
    REJECTED: 'REJECTED'
}

class llsPromise {
    constructor(executor) {
        //最初始状态
        this.state = STATUS.PENDING;
        this.value = undefined;  //值或者终值
        this.reason = undefined; //拒因或者失败原因

        const resolve = function (value) { // resolve函数,功能是扭转状态为fulFilled&设置终值
            if(this.state === STATUS.PENDING) {
                this.state = STATUS.FULFILLED;
                this.value = value;
            }
        }.bind(this)

        const reject = function (reason) { // reject函数,功能是扭转状态为rejected&设置拒因
            if(this.state === STATUS.PENDING) {
                this.state = STATUS.REJECTED;
                this.reason = reason;
            }
        }.bind(this)

        try{ //捕获异常,并执行reject,保存错误的时候扭转状态为rejected&设置拒因
            executor(resolve, reject);
        }catch(e){
            reject(e);
        }
    }
    //接受两个参数 onFulfilled和onRejected
    then(onFulfilled, onRejected) {
        if(this.state === STATUS.FULFILLED && onFulfilled && isFunction(onFulfilled)) {
            //接收 promise 的终值
            onFulfilled(this.value);
        }

        if(this.state === STATUS.REJECTED && onRejected && isFunction(onRejected)) {
            //接收 promise 的拒因
            onRejected(this.reason);
        }
    }
}

function isFunction(value) {
    return typeof value === 'function' && typeof value.nodeType !== 'number';
}

测试一下,符合预期,一个最简单的Promise就实现了

let promise1 = new llsPromise((resolve, reject) => {
    resolve('llsPromise resolve: lls value is OK~');
    //reject('llsPromise reject: lls reason is Fail~');
    //throw new Error('Sorry lls is Error~')
});

promise1.then(value => {
    console.log(`onFulfilled:`, value);
}, (reason) => {
    console.log(`onRejected:`, reason);
});
//分别打印出
//onFulfilled:llsPromise  resolve: lls value is OK~
//onRejected:llsPromise  reject: lls reason is Fail~
//onRejected:llsPromise  Error: Sorry lls is Error~

3、上面的Promise能够处理异步吗?

试一下~

let promise1 = new llsPromise((resolve, reject) => {
    setTimeout(() => {
        resolve('llsPromise resolve: lls value is OK~');
        //reject('llsPromise reject: lls reason is Fail~');
        //throw new Error('Sorry lls is Error~')  
    }, 2000);
});

promise1.then(value => {
    console.log(`onFulfilled:`, value);
}, (reason) => {
    console.log(`onRejected:`, reason);
});
// 打印不出任何东西

显然是不满足需求的,那到底是为啥?

原因由于resolve或者reject是异步执行的,当执行到then的时候,状态还未改变,因此: onFulfilled(this.value) 和 onRejected(this.reason)都不会执行

then(onFulfilled, onRejected) {
    
    if(this.state === STATUS.FULFILLED && onFulfilled && isFunction(onFulfilled)) {
        //接收 promise 的终值
        onFulfilled(this.value);
    }

    if(this.state === STATUS.REJECTED && onRejected && isFunction(onRejected)) {
        //接收 promise 的拒因
        onRejected(this.reason);
    }
}

该怎么解决呢?

思考一下,最好是能够知道什么时候状态改变,然后执行对应的onFulfilled或者onRejected回调,而状态的改变在resolve和reject方法中,因此可以在这两个方法中调用对应的onFulfilled或者onRejected回调;但是需要把回调存储起来,代码改变如下:

1、新增onFulfilledCallbacks和onRejectedCallbacks用于存储onFulfilled或者onRejected回调

//存储异步回调,为啥用数组,是因为promise实例可以多次调then, 
this.onFulfilledCallbacks = []; 
this.onRejectedCallbacks = [];

2、将onFulfilled回调存储在onFulfilledCallbacks中,将onFulfilled回调存储在onFulfilledCallbacks中

if(onFulfilled && isFunction(onFulfilled)) {
    //将onFulfilled回调存储在onFulfilledCallbacks中
    this.onFulfilledCallbacks.push(() => {
        onFulfilled(this.value);
    });
}

if(onRejected && isFunction(onRejected)) {
    //将onFulfilled回调存储在onFulfilledCallbacks中
    this.onRejectedCallbacks.push(() => {
        onRejected(this.reason);
    });
}

3、执行onFulfilledCallbacks和onRejectedCallbacks回调函数

const resolve = function (value) {
    if(this.state === STATUS.PENDING) {
        this.state = STATUS.FULFILLED;
        this.value = value;
        //执行onFulfilledCallbacks
        this.onFulfilledCallbacks.forEach(cb => {
            cb();
        });
    }
}.bind(this)

const reject = function (reason) {
    if(this.state === STATUS.PENDING) {
        this.state = STATUS.REJECTED;
        this.reason = reason;
        //执行onFulfilledCallbacks
        this.onRejectedCallbacks.forEach(cb => {
            cb();
        });
    }
}.bind(this)

完整代码如下~

//状态枚举
const STATUS = {
    PENDING: 'PENDING',
    FULFILLED: 'FULFILLED',
    REJECTED: 'REJECTED'
}

class llsPromise {
    constructor(executor) {
        //最初始状态
        this.state = STATUS.PENDING;
        this.value = undefined;  //值或者终值
        this.reason = undefined; //拒因或者失败原因
        //存储异步回调,为啥用数组,是因为promise实例可以多次调then,
        this.onFulfilledCallbacks = [];
        this.onRejectedCallbacks = []; 

        const resolve = function (value) { // resolve函数,功能是扭转状态为fulFilled&设置终值
            if(this.state === STATUS.PENDING) {
                this.state = STATUS.FULFILLED;
                this.value = value;
                this.onFulfilledCallbacks.forEach(cb => {
                    cb();
                });
            }
        }.bind(this)

        const reject = function (reason) { // reject函数,功能是扭转状态为rejected&设置拒因
            if(this.state === STATUS.PENDING) {
                this.state = STATUS.REJECTED;
                this.reason = reason;
                this.onRejectedCallbacks.forEach(cb => {
                    cb();
                });
            }
        }.bind(this)

        try{ //捕获异常,并执行reject,保存错误的时候扭转状态为rejected&设置拒因
            executor(resolve, reject);
        }catch(e){
            reject(e);
        }
    }
    //接受两个参数 onFulfilled和onRejected
    then(onFulfilled, onRejected) {
        if(onFulfilled && isFunction(onFulfilled)) {
            //将onFulfilled回调存储在onFulfilledCallbacks中
            this.onFulfilledCallbacks.push(() => {
                onFulfilled(this.value);
            });
        }

        if(onRejected && isFunction(onRejected)) {
            //将onFulfilled回调存储在onFulfilledCallbacks中
            this.onRejectedCallbacks.push(() => {
                onRejected(this.reason);
            });
        }
    }
}

function isFunction(value) {
    return typeof value === 'function' && typeof value.nodeType !== 'number';
}

再执行下异步的代码,就会符合预期结果

4、总结

这样就初步实现了Promise的基本的功能,关于then 方法必须返回一个 promise 对象的实现将在下一篇高级开发者必须掌握的手写Promise终结篇(附源码)实现~