尝试手写Promise

160 阅读12分钟

Promise解析

MDN 描述:一个 Promise 对象代表一个在这个 promise 被创建出来时不一定已知的值。它让您能够把异步操作最终的成功返回值或者失败原因和相应的处理程序关联起来。 这样使得异步方法可以像同步方法那样返回值:异步方法并不会立即返回最终的值,而是会返回一个 promise,以便在未来某个时候把值交给使用者。

具体用法就不写了:可以去MDN看 developer.mozilla.org/zh-CN/docs/…

这里主要是写源码:

Promise对象有以下两个特点。

(1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。

(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。

这里编写一个MyPromise

编写思路:

基本用法:

let promise=new Promise((resolve,reject) => {
		if(...){
		//状态从`pending`变为`fulfilled`
			resolve(value)
		}else {
		//状态从`pending`变为`rejected`。
			reject(err)
		}
})
promise.then(value=>{
   
})
  1. 从用法中可以看到,Promise有三个状态,pending(进行中)、fulfilled(已成功)和rejected(已失败),那么就需要一个状态值表示当前Promise的状态,然后Promise的构造函数中接收一个回调函数,而这个回调函数有两个参数,这两个参数是两个方法,当使用resolve方法时,状态从pending变为fulfilled,并把resolve方法中的参数传递到后面的then方法中。所以这个自定义的MyPromise还有一个then方法,还要有两个值分别保存resolve方法和reject方法传出的值。
//先编写表示状态值的常量
const Pending = "pending";
const Fulfilled = "fulfilled";
const Rejected = "rejected";
class MyPromise {
  constructor(callback) {
        this._state = Pending;
      //保存resolve传出的值
        this._value = undefined;
      //保存reject传出的值
        this._reason = undefined;
          let resolve = (value) => {
              
        }
        let reject = (err) => {
            
        }
    }
    
    then(fulfilledCallback,rejectedCallback){
        
    }
    
}

上面代码就是基本结构:然后实现功能,当执行resolve时,把状态改为fulfilled,并执行then方法里的回调,当执行reject时,状态改为rejected,并执行then方法里的第二个回调,因为then方法可以多次调用,然后当状态为filfilled时,回调才会执行,所以需要数组缓存这个回调方法,这里用successCallback和 failureCallback 存放相应的回调。由于promise回调任务是微队列任务,在eventLoop中,微队列任务会在上宏任务执行完后,下一个宏任务执行前执行,所以用setTimeout(callback,0)来模拟这个eventLoop。

 setTimeout(() => {
                    let cb;
                    //当执行一个回调函数后,就删除缓存数组中的一项,直到数组清空;
                    while (cb = this._successCallback.shift()) {
                        cb(value)
                    }
                }, 0)

构造函数

    constructor(callback) {
        this._successCallback = [];
        this._failureCallback = [];
        this._state = Pending;
        this._value = undefined;
        this._reason = undefined;
        let resolve = (value) => {
            if (this._state === Pending) {
                setTimeout(() => {
                       this._state = Fulfilled;
                		this._value = value;
                    let cb;
                    while (cb = this._successCallback.shift()) {
                        cb(value)
                    }
                }, 0)
            }
        }
        let reject = (reason) => {
            if (this._state === Pending) {
              
                setTimeout(() => {
                    this._state = Rejected;
                	this._reason = reason;
                    let cb;
                    while (cb = this._failureCallback.shift()) {
                        cb(reason)
                    }
                }, 0)
            }
        }

     
    }

这样,就把构造函数的方法和属性都写好了,下一步就是执行构造函数中参数的方法了

function isFunction(obj) {
    return Object.prototype.toString.call(obj) === '[object Function]';
}
try {
    if (isFunction(callback)) {
        //这里,把构造函数中传入的参数回调进行执行
        callback(resolve, reject)
    }
} catch (e) {
    console.log(e)
    reject(e)
}

这样要判断,构造函数中的参数是否是函数,如果不是函数就将不作处理,在Promise中是必须要传入函数的。

不然会有错误:  TypeError: Promise resolver undefined is not a function

现在就把MyPromise构造函数编写好了

constructor(callback) {
        this._successCallback = [];
        this._failureCallback = [];
        this._state = Pending;
        this._value = undefined;
        this._reason = undefined;
        let resolve = (value) => {
            if (this._state === Pending) {
                setTimeout(() => {
                   	this._state = Fulfilled;
                	this._value = value;
                    let cb;
                    while (cb = this._successCallback.shift()) {
                        cb(value)
                    }
                }, 0)
            }
        }
        let reject = (reason) => {
            if (this._state === Pending) {
                setTimeout(() => {
                    this._state = Rejected;
               		 this._reason = reason;
                    let cb;
                    while (cb = this._failureCallback.shift()) {
                        cb(reason)
                    }
                }, 0)

            }
        }
        try {
            if (isFunction(callback)) {
                callback(resolve, reject)
            }
        } catch (e) {
            console.log(e)
            reject(e)
        }
    }

then方法

Promise 对象的 then 方法接受两个参数:

then(fulfilledCallback,rejectedCallback){}

fulfilledCallbackrejectedCallback 都是可选参数。

  • 如果 fulfilledCallbackrejectedCallback 不是函数,其必须被忽略

fulfilledCallback 特性

如果 fulfilledCallback 是函数:

  • promise 状态变为成功时必须被调用,其第一个参数为 promise 成功状态传入的值( resolve 执行时传入的值)
  • promise 状态改变前其不可被调用
  • 其调用次数不可超过一次

rejectedCallback 特性

如果rejectedCallback  是函数:

  • promise 状态变为失败时必须被调用,其第一个参数为 promise 失败状态传入的值( reject 执行时传入的值)
  • promise 状态改变前其不可被调用
  • 其调用次数不可超过一次

多次调用

then 方法可以被同一个 promise 对象调用多次

  • promise 成功状态时,所有 fulfilledCallback 需按照其注册顺序依次回调
  • promise 失败状态时,所有 rejectedCallback 需按照其注册顺序依次回调

返回

then 方法必须返回一个新的 promise 对象

promise2 = promise1.then(fulfilledCallback , rejectedCallback );
复制代码

因此 promise 支持链式调用

promise1.then(fulfilledCallback , rejectedCallback).then(fulfilledCallback, rejectedCallback);
复制代码

这里涉及到 Promise 的执行规则,包括“值的传递”和“错误捕获”机制:

1、如果 onFulfilled 或者 onRejected 返回一个值 x ,则运行下面的 Promise 解决过程:[[Resolve]](promise2, x)

  • x 不为 Promise ,则使 x 直接作为新返回的 Promise 对象的值, 即新的fulfilledCallback或者 rejectedCallback 函数的参数.
  • xPromise ,这时后一个回调函数,就会等待该 Promise 对象(即 x )的状态发生变化,才会被调用,并且新的 Promise 状态和 x 的状态相同。

简单来说,就是一个then方法返回一个新的promise对象,这个对象的状态是Pending

console.log(new Promise((resolve) => {
    resolve(1)
}).then(()=>{
}));  //Promise { <pending> }

当then中的参数方法,就是fulfilledCallback或者rejectedCallback执行后,根据方法的返回值来更改新promise对象的状态值。

如果有then的回调是一个函数,又不是promise对象,则会将该新promise状态改为fulfilled,并把return 的内容作为value传递给下一个then方法。

let promise=new Promise((resolve) => {
    resolve(1)
})
promise.then((value) => {
    return 'new Promise value'
    //这个新的promise对象传递的值是return 里的内容
}).then(value => {
    console.log(value)
});

如果then的回调是一个函数,return是一个promise对象,则新prmise对象的状态依赖这个返回的promise对象

let promise=new Promise((resolve) => {
    resolve(1)
})
promise.then((value) => {
    return new Promise(()=>{}) //当这个promise的状态改为fulfilled,下面的then回调才会执行
}).then(value => {
    console.log(value)
});

如果then的回调不是一个函数,则将当前then的value传递给下一个then。

let promise=new Promise((resolve) => {
    resolve(1)
})
promise.then()//value向下传递
    .then(value => {
    console.log(value) //value is 1
});

根据这些特性,可以编写then方法了:

then(fulfilledCallback, rejectedCallback) {
    const {_state, _value, _reason} = this
    return new MyPromise((resolve, reject) => {

        //状态为fulfilled的处理方法
        let handlerFulfilled = (value) => {
            
            //回调不是个函数,则直接传递值
            if (!isFunction(fulfilledCallback)) {
                resolve(value);
                return;
            }
            try {
                //执行回调,拿到返回结果
                let result = fulfilledCallback(value);
                if (result instanceof MyPromise) {
                  //依赖返回的MyPromise对象状态,返回的MyPromise对象状态改变,则当前新的promise对象状态改变
                    result.then(resolve, reject);
                    return;
                }
                //将结果传递出去
                resolve(result);

            } catch (e) {
                //将异常传递
                reject(e);
            }
        }

        //状态为rejected的处理方法
        let handlerRejected = (error) => {
            try {
                if (!isFunction(rejectedCallback)) {
                    reject(error);
                    return;
                }
                let result = rejectedCallback(error);
                if (result instanceof MyPromise) {
                    //依赖返回的MyPromise对象状态,返回的MyPromise对象状态改变,则当前新的promise对象状态改变
                    result.then(resolve, reject);
                    return;
                }
                reject(result);

            } catch (e) {
                reject(e);
            }
        }
        
        switch (_state) {
            case Pending:
                //将要执行的方法放进队列中缓存
                this._successCallback.push(handlerFulfilled);
                this._failureCallback.push(handlerRejected);
                break;
            case Fulfilled:
                //直接执行
                handlerFulfilled(_value);
                break;
            case Rejected:
                 //直接执行
                handlerRejected(_reason);
                break;
        }

    });
}

catch方法

Promise.prototype.catch()方法是.then(null, rejection).then(undefined, rejection)的别名,用于指定发生错误时的回调函数。

catch(rejectedCallback) {
    return this.then(null, rejectedCallback);
}

finally方法

finally本质上是then方法的特例。

finally(finallyCallback) {
    return this.then(finallyCallback, finallyCallback)
}

静态 resolve 方法

static resolve(params) {
    //1.如果参数是 Promise 实例,那么`Promise.resolve`将不做任何修改、原封不动地返回这个实例。
    if (params instanceof MyPromise) {
        return params;
    }
    return new MyPromise((resolve, reject) => {
   //1.如果参数是 thenable对象,那么将resolve和rejected参数将执行thenable对象的then方法,并返回一个新的MyPromise对象。
        if (typeof params==='object'&&Reflect.has(params, 'then') && isFunction(params.then)) {
            params.then(resolve, reject)
        } else {
            //其他情况则将值传递出去,并返回一个状态为fulfilled的MyPromise对象
            resolve(params)
        }
    })
}

静态 reject方法

static reject(params) {
    
    //1.如果参数是 Promise 实例,那么`Promise.resolve`将不做任何修改、原封不动地返回这个实例。
    if (params instanceof MyPromise) {
        return params;
    }
    return new MyPromise((resolve, reject) => {
  //1.如果参数是 thenable对象,那么将resolve和rejected参数将执行thenable对象的then方法,并返回一个新的MyPromise对象
        if (Reflect.has(params, 'then') && isFunction(params.then)) {
            params.then(resolve, reject)
        } else {
            //其他情况则将值传递出去,并返回一个状态为rejected的MyPromise对象
            reject(params)
        }
    })
}

静态 all方法

Promise.all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。

all返回的新Promise实例状态由参数中数组的promise实例决定,如果数组中的实例有一个

static all(arr = []) {
    //代表代表fulfilled状态的promise实例数量状态的MyPromise实例数量
    let resolveNum = 0;
    //将fulfilled状态的传递的值用数组保存
    let valueArr=[]
    //表示fulfilled状态的MyPromise实例的数量需要达到这个值才能把这个all方法的MyPromise 的状态改为fulfilled
    let needResolveNum = arr.length
    return new MyPromise((resolve, reject) => {
        for (const item of arr) {
            //将参数数组中的每一项都变成MyPromise对象,如果本身就是MyPromise对象,则直接返回这个MyPromise对象
            let promise = MyPromise.resolve(item)
            promise.then((value) => {
                resolveNum++
                valueArr.push(value)
                if (resolveNum === needResolveNum) {
                  //当参数数组中所有的MyPromise实例状态都为fulfilled,则把这个all方法的MyPromise 的状态改为fulfilled
                    resolve(valueArr)
                }
            },(err) => {
                //当一个MyPromise实例的状态为rejected,则直接把这个all方法返回的MyPromise实例状态改为rejected
                reject(err)
             
            })
        }

    })
}

静态race方法

Promise.race()方法用于将多个 Promise 实例进行比较,当有一个promise实例状态改变,则直接把值传递出去,成为新promise实例的状态值。

static race(arr = []) {
    return new MyPromise((resolve, reject) => {
        for (const item of arr) {
            //将参数数组中的每一项都变成MyPromise对象,如果本身就是MyPromise对象,则直接返回这个MyPromise对象
            let promise = MyPromise.resolve(item)
            promise.then((value) => {     
               //当一个MyPromise实例的状态为fulfilled,则直接把这个all方法返回的MyPromise实例状态改为fulfilled
                    resolve(value)
            },(err) => {
                //当一个MyPromise实例的状态为rejected,则直接把这个all方法返回的MyPromise实例状态改为rejected
                reject(err)
             
            })
        }

    })
}

最终代码

const Pending = "pending";
const Fulfilled = "fulfilled";
const Rejected = "rejected";

function isFunction(params) {
    return Object.prototype.toString.call(params) === '[object Function]';
}

class MyPromise {
    constructor(callback) {
        this._successCallback = [];
        this._failureCallback = [];
        this._state = Pending;
        this._value = undefined;
        this._reason = undefined;
        let resolve = (value) => {
            if (this._state === Pending) {

                setTimeout(() => {
                    this._state = Fulfilled;
                    this._value = value;
                    let cb;
                    while (cb = this._successCallback.shift()) {
                        cb(value)
                    }
                }, 0)
            }
        }
        let reject = (reason) => {
            if (this._state === Pending) {

                setTimeout(() => {
                    this._state = Rejected;
                    this._reason = reason;
                    let cb;
                    while (cb = this._failureCallback.shift()) {
                        cb(reason)
                    }
                }, 0)

            }
        }

        try {
            if (isFunction(callback)) {
                callback(resolve, reject)
            }
        } catch (e) {
            console.log(e)
            reject(e)
        }
    }

    then(fulfilledCallback, rejectedCallback) {
        const {_state, _value, _reason} = this
        return new MyPromise((resolve, reject) => {

            //状态为fulfilled的处理方法
            let handlerFulfilled = (value) => {

                //回调不是个函数,则直接传递值
                if (!isFunction(fulfilledCallback)) {
                    resolve(value);
                    return;
                }
                try {
                    //执行回调,拿到返回结果
                    let result = fulfilledCallback(value);
                    if (result instanceof MyPromise) {
                        //依赖返回的MyPromise对象状态,返回的MyPromise对象状态改变,则当前新的promise对象状态改变
                        result.then(resolve, reject);
                        return;
                    }
                    //将结果传递出去
                    resolve(result);

                } catch (e) {
                    //将异常传递
                    reject(e);
                }
            }

            //状态为rejected的处理方法
            let handlerRejected = (error) => {
                try {
                    if (!isFunction(rejectedCallback)) {
                        reject(error);
                        return;
                    }
                    let result = rejectedCallback(error);
                    if (result instanceof MyPromise) {
                        //依赖返回的MyPromise对象状态,返回的MyPromise对象状态改变,则当前新的promise对象状态改变
                        result.then(resolve, reject);
                        return;
                    }
                    reject(result);

                } catch (e) {
                    reject(e);
                }
            }

            switch (_state) {
                case Pending:
                    //将要执行的方法放进队列中缓存
                    this._successCallback.push(handlerFulfilled);
                    this._failureCallback.push(handlerRejected);
                    break;
                case Fulfilled:
                    //直接执行
                    handlerFulfilled(_value);
                    break;
                case Rejected:
                    //直接执行
                    handlerRejected(_reason);
                    break;
            }

        });
    }
    catch(rejectedCallback) {
        return this.then(null, rejectedCallback);
    }

    finally(finallyCallback) {
        return this.then(finallyCallback, finallyCallback)
    }

    static resolve(params) {
        //1.如果参数是 Promise 实例,那么`Promise.resolve`将不做任何修改、原封不动地返回这个实例。
        if (params instanceof MyPromise) {
            return params;
        }
        return new MyPromise((resolve, reject) => {
            //1.如果参数是 thenable对象,那么将resolve和rejected参数将执行thenable对象的then方法,并返回一个新的MyPromise对象。
            if (typeof params==='object'&&Reflect.has(params, 'then') && isFunction(params.then)) {
                params.then(resolve, reject)
            } else {
                //其他情况则将值传递出去,并返回一个状态为fulfilled的MyPromise对象
                resolve(params)
            }
        })
    }

    static reject(params) {

        //1.如果参数是 Promise 实例,那么`Promise.resolve`将不做任何修改、原封不动地返回这个实例。
        if (params instanceof MyPromise) {
            return params;
        }
        return new MyPromise((resolve, reject) => {
            //1.如果参数是 thenable对象,那么将resolve和rejected参数将执行thenable对象的then方法,并返回一个新的MyPromise对象
            if (Reflect.has(params, 'then') && isFunction(params.then)) {
                params.then(resolve, reject)
            } else {
                //其他情况则将值传递出去,并返回一个状态为rejected的MyPromise对象
                reject(params)
            }
        })
    }

    static all(arr = []) {
        //代表代表fulfilled状态的promise实例数量状态的MyPromise实例数量
        let resolveNum = 0;
        //将fulfilled状态的传递的值用数组保存
        let valueArr=[]
        //表示fulfilled状态的MyPromise实例的数量需要达到这个值才能把这个all方法的MyPromise 的状态改为fulfilled
        let needResolveNum = arr.length
        return new MyPromise((resolve, reject) => {
            for (const item of arr) {
                //将参数数组中的每一项都变成MyPromise对象,如果本身就是MyPromise对象,则直接返回这个MyPromise对象
                let promise = MyPromise.resolve(item)
                promise.then((value) => {
                    resolveNum++
                    valueArr.push(value)
                    if (resolveNum === needResolveNum) {
                        //当参数数组中所有的MyPromise实例状态都为fulfilled,则把这个all方法的MyPromise 的状态改为fulfilled
                        resolve(valueArr)
                    }
                },(err) => {
                    //当一个MyPromise实例的状态为rejected,则直接把这个all方法返回的MyPromise实例状态改为rejected
                    reject(err)

                })
            }

        })
    }
    static race(arr = []) {
        return new MyPromise((resolve, reject) => {
            for (const item of arr) {
                //将参数数组中的每一项都变成MyPromise对象,如果本身就是MyPromise对象,则直接返回这个MyPromise对象
                let promise = MyPromise.resolve(item)
                promise.then((value) => {
                    //当一个MyPromise实例的状态为fulfilled,则直接把这个all方法返回的MyPromise实例状态改为fulfilled
                    resolve(value)
                },(err) => {
                    //当一个MyPromise实例的状态为rejected,则直接把这个all方法返回的MyPromise实例状态改为rejected
                    reject(err)
                })
            }
        })
    }

    }

参考

作者:面条__
链接:juejin.cn/post/684490…
来源:稀土掘金

MDN: developer.mozilla.org/zh-CN/docs/…

阮一峰es6教程:es6.ruanyifeng.com/#docs/promi…