美文网首页
实现一个符合 Promise/A+ 规范的 MyPromise

实现一个符合 Promise/A+ 规范的 MyPromise

作者: 跟篮球结婚 | 来源:发表于2018-01-12 19:26 被阅读0次

    Promise

    实现一个符合 Promise/A+ 规范的 MyPromise,并实现 resolve、reject、all、race、defer、deferred等静态方法。

    MyPromise

    1. 作用:创建 MyPromise实例。Promise

    2. MyPromise接收一个回掉函数 executor

    3. MyPromise状态

      • pending

        • 可以转换成 fulfilled 或 rejected
      • fulfilled

        • 不可改变成其他状态
      • rejected

        • 不可改变成其他状态
    4. onFulfilledCallbacksonRejectedCallbacks

      • 两个数组,数组每一项是一个函数。分别接收then里面的第一个参数和第二个参数。

      • 状态是 pending 的回掉函数。

    5. resolve

      • promise的状态是fulfilled异常是的处理函数

      • 接收 value 参数

        • 如果是promise,执行then

        • 如果不是promise,把value做为参数传给onFulfilledCallbacks里的每个函数。

    6. reject

      • promise的状态是rejected异常是的处理函数

      • 接收 reason 参数,把reason做为参数传给onRejectedCallbacks里的每个函数。

    7. 执行 executor,如果有异常,抛给reject

    8. 因为Promise是在同步代码执行完成后再执行,所以要把Mypromise的执行方法resolvereject放在异步队列里

    
    function MyPromise(executor) {
    
        if (typeof executor !== 'function') {
    
            throw new TypeError('Promise resolver ' + executor + ' is not a function');
    
        }
    
        let self = this;
    
        this.status = 'pending';
    
        this.value = undefined;
    
        this.reason = undefined;
    
        this.onFulfilledCallbacks = [];
    
        this.onRejectedCallbacks = [];
    
        function resolve(value) {
            if (value instanceof MyPromise) {
                return value.then(resolve, reject);
            }
            if (self.status === 'pending') {            
                self.value = value;
                self.status = 'fulfilled';
                self.onFulfilledCallbacks.forEach(item => item(value));
            }
        }
        
        function reject(reason) {
            if (self.status === 'pending') {
                self.reason = reason;
                self.status = 'rejected';
                self.onRejectedCallbacks.forEach(item => item(reason));
            }
        }
    
    
        try {
    
            executor(resolve, reject);
    
        } catch (e) {
    
            reject(e);
    
        }
    
    }
    
    

    MyPromise.prototype.then

    1. 作用:接收两个函数参数,第一个函数的参数是 resolve传入的参数,第二个参数是 reject传入的参数。Promise#then

    2. onFulfilled

      • MyPromise 成功时执行的方法

      • resolve 的参数会作为value传给 onFulfilled

    3. onRejected

      • MyPromise 失败时执行的方法

      • reject 的参数会作为value传给 onRejected

    4. 返回一个 MyPromise 实例 newPromise,方便链式调用

    5. 对三种状态分别处理

      • 每个状态中创建 newPromise

      • fulfilled

        • 直接执行 onFulfilled,返回值x

        • newPromisex以及newPromise里的resolvereject做为参数传给 resolutionPromise

        • 把 MyPromise 的参数放在异步队列里

      • rejected

        • 直接执行 onRejected,返回值x

        • newPromisex以及newPromise里的resolvereject做为参数传给 resolutionPromise

        • 把 MyPromise 的参数放在异步队列里

      • pending

        • 状态待定,把fulfilledrejected里的异步函数分别加到 onFulfilledCallbacksonRejectedCallbacks的最后一位
    6. resolutionPromise 后面细说

    7. catch捕获异常,执行 reject

    
    MyPromise.prototype.then = function (onFulfilled, onRejected) {
    
        let self = this;
    
        typeof onFulfilled !== 'function' && (onFulfilled = function (value) {
    
            return value;
    
        });
    
        typeof onRejected !== 'function' && (onRejected = function (reason) {
    
            throw reason;
    
        });
    
        let newPromise;
    
        /**
    
        *  分别处理实例的三种状态
    
        */
    
        if (self.status === 'fulfilled') {
    
            newPromise = new MyPromise(function (resolve, reject) {
    
                setTimeout(function () {
    
                    try {
    
                        let x = onFulfilled(self.value);
    
                        resolutionPromise(newPromise, x, resolve, reject);
    
                    } catch (e) {
    
                        reject(e);
    
                    }
    
                });
    
            });
    
        }
    
        if (self.status === 'rejected') {
    
            newPromise = new MyPromise(function (resolve, reject) {
    
                setTimeout(function () {
    
                    try {
    
                        let x = onRejected(self.reason);
    
                        resolutionPromise(newPromise, x, resolve, reject);
    
                    } catch (e) {
    
                        reject(e);
    
                    }
    
                });
    
            });
    
        }
    
        if (self.status === 'pending') {
    
            newPromise = new MyPromise(function (resolve, reject) {
    
                self.onFulfilledCallbacks.push(function (value) {
    
                    setTimeout(function () {
    
                        try {
    
                            let x = onFulfilled(value);
    
                            resolutionPromise(newPromise, x, resolve, reject);
    
                        } catch (e) {
    
                            reject(e);
    
                        }
    
                    });
    
                });
    
                self.onRejectedCallbacks.push(function (reason) {
    
                    setTimeout(function () {
    
                        try {
    
                            let x = onRejected(reason);
    
                            resolutionPromise(newPromise, x, resolve, reject);
    
                        } catch (e) {
    
                            reject(e);
    
                        }
    
                    });
    
                });
    
            });
    
        }
    
        return newPromise;
    
    };
    
    

    MyPromise.prototype.catch

    1. 作用:捕获异常

    2. 返回 MyPromise

    
    MyPromise.prototype.catch = function (onRejected) {
    
        return this.then(undefined, onRejected);
    
    };
    
    

    The Promise Resolution Procedure

    1. Promise解析过程,是以一个 promise、一个值 xresolve, reject做为参数的抽象过程

    2. promise 等于 xreject 抛出异常 new TypeError('循环引用')

    3. x如果不是对象(不包括 null)或者函数,执行 resolve(x)

    4. 获取 x.then 赋值给 then

      • then 如果是 function

        • x做为 this 调用then,第一个参数是 resolvePromise,第二个参数是 rejectPromise

        • resolvePromiserejectPromise只有第一次调用有效

        • resolvePromise参数为 y,执行 resolutionPromise(promise, y, resolve, reject)

        • rejectPromise参数为 r,执行 reject(r)

      • then 如果不是 function

        • 执行 resolve(x)
    5. 用捕获上一步的异常

      • 执行 reject(e)

      • 如果执行过 resolvePromiserejectPromise,忽略

    
    function resolutionPromise(promise, x, resolve, reject) {
    
        if (promise === x) {
    
            reject(new TypeError('循环引用'));
    
        }
    
        let then, called;
    
        if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
    
            try {
    
                then = x.then;
    
                if (typeof then === 'function') {
    
                    then.call(x, function (y) {
    
                        if (called)
    
                            return;
    
                        called = true;
    
                        resolutionPromise(promise, y, resolve, reject);
    
                    }, function (r) {
    
                        if (called)
    
                            return;
    
                        called = true;
    
                        reject(r);
    
                    })
    
                } else {
    
                    resolve(x);
    
                }
    
            } catch (e) {
    
                if (called)
    
                    return;
    
                reject(e);
    
            }
    
        } else {
    
            resolve(x);
    
        }
    
    }
    
    

    MyPromise 静态方法

    MyPromise.all

    
    MyPromise.all = function (promises) {
    
        let called = false;
    
        return new MyPromise(function (resolve, reject) {
    
            let newArr = [], count = 0;
    
            for (let i = 0; i < promises.length; i++) {
    
                let item = promises[i];
    
                if (!(item instanceof MyPromise)) {
    
                    item = MyPromise.resolve(item);
    
                }
    
                item.then(function (data) {
    
                    if (!called) {
    
                        newArr[i] = data;
    
                        if (i == count) {
    
                            resolve(newArr);
    
                            count++;
    
                        }
    
                    }
    
                }, function (e) {
    
                    if (!called) {
    
                        reject(e);
    
                        called = true;
    
                    }
    
                });
    
            }
    
        });
    
    };
    
    

    MyPromise.race

    
    MyPromise.race = function (promises) {
    
        return new MyPromise(function (resolve, reject) {
    
            let called = false;
    
            for (let i = 0; i < promises.length; i++) {
    
                let item = promises[i];
    
                if (!(item instanceof MyPromise)) {
    
                    item = MyPromise.resolve(item);
    
                }
    
                item.then(function (data) {
    
                    if (!called) {
    
                        resolve(data);
    
                        called = true;
    
                    }
    
                }, function (e) {
    
                    if (!called) {
    
                        reject(e);
    
                        called = true;
    
                    }
    
                });
    
            }
    
        })
    
    };
    
    

    MyPromise.resolve

    
    MyPromise.resolve = function (value) {
    
        if (value instanceof MyPromise) {
    
            return value;
    
        }
    
        return new MyPromise(function (resolve, reject) {
    
            if (typeof value !== null && typeof value === 'object' && typeof value.then === 'function') {
    
                value.then();
    
            } else {
    
                resolve(value);
    
            }
    
        })
    
    };
    
    

    MyPromise.reject

    
    MyPromise.reject = function (e) {
    
        return new MyPromise(function (resolve, reject) {
    
            reject(e);
    
        })
    
    };
    
    

    test

    • npm i -g promises-aplus-tests

    • promises-aplus-tests Promise.js

    源码

    参考资料

    相关文章

      网友评论

          本文标题:实现一个符合 Promise/A+ 规范的 MyPromise

          本文链接:https://www.haomeiwen.com/subject/ewtqoxtx.html