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

一个符合 Promise/A+ 规范的 Promise

作者: 天上月丶 | 来源:发表于2019-04-11 11:52 被阅读0次
    // 表示状态,便于后期维护
    const PENDING = 'pending';
    const RESOLVED = 'resolved';
    const REJECTED = 'rejected';
    
    function MyPromise(fn) {
        // 因代码可能会异步执行,用于获取正确的this对象
        const that = this;
        // 初始状态为pending
        that.state = PENDING;
        // 用于保存resolve 或者 reject 中传入的值
        that.value = null;
        // 用于保存then中的回调,因为当执行完Promise时状态可能还是等待中,
        // 这时候应该把then中的回调保存起来用户状态改变时使用
        that.resolvedCallbacks = [];
        that.rejectedCallbacks = [];
    
        // 首先两个函数都得判断当前状态是否是等待中,因为只有等待状态可以改变状态
        // 将当前状态更改为对应状态,并且将传入的值赋值给value
        // 遍历回调数组并执行
        function resolve(value) {
            // 首先需要判断传入的值是否为Promise类型
            if(value instanceof MyPromise) {
                return value.then(resolve, reject)
            }
            // 为了保证函数执行顺序,需要将函数整体代码用setTimeout包裹起来
            setTimeout(() => {
                if(that.state === PENDING) {
                    that.state = RESOLVED;
                    that.value = value;
                    that.resolvedCallbacks.map(cb => cb(that.value));
                }
            }, 0);
        }
    
        function reject(value) {
            setTimeout(() => {
                if(that.state === PENDING) {
                    that.state = REJECTED;
                    that.value = value;
                    that.rejectedCallbacks.map(cb => cb(that.value));
                }
            }, 0);
        }
    
        // 执行传入的参数并且将之前的两个函数当做参数传进去
        // 注意: 可能执行函数过程中会遇到错误,需要捕获错误并执行reject函数
        try{
            fn(resolve, reject)
        } catch (e) {
            reject(e);
        }
    }
    
    
    MyPromise.prototype.then = function(onFulfilled, onRejected) {
        const that = this;
        // 首先判断两个参数是否为函数类型,因为这两个参数时可选参数
        // 当参数不是函数类型时,需要创建一个函数赋值给对应的参数,同时也实现了透传
        // eg: Promise.resolve(4).then().then(value => console.log(value))
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v;
        onRejected = typeof onRejected === 'function' ? onRejected : r => { throw r; };
    
        let promise2;
    
        // 判断状态
        // 当状态不是等待态时,就去执行相应的函数。
        // 如果状态是等待态的话,就往回调函数中push函数
        if(that.state === PENDING) {
            // 返回一个新的Promise对象,并在Promise中传入了一个函数
            // 函数的基本逻辑和之前一样,往回调数组中push函数
            // 同样,在执行函数的过程中可能会遇到错误,所以使用了try ... catch 包裹
            // 规范规定,执行onFulfilled 或者 onRejected 函数时会返回一个X,
            // 并且执行Promise解决过程,这是为了不同的Promise都可以兼容使用
            return (promise2 = new MyPromise((resolve, reject) => {
                that.resolvedCallbacks.push(() => {
                    try {
                        const x = onFulfilled(that.value);
                        resolutionProcedure(promise2, x, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }
                });
    
                that.rejectedCallbacks.push(() => {
                    try {
                        const x = onRejected(that.value);
                        resolutionProcedure(promise2, x, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }
                })
            }));
        }
    
        if(that.state === RESOLVED) {
            // 规范规定,传入的函数体需要异步执行
            return (promise2 = new MyPromise((resolve, reject) => {
                setTimeout(() => {
                    try {
                        const x = onFulfilled(that.value);
                        resolutionProcedure(promise2, x, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }
                })
            }));
            // onFulfilled(that.value);
        }
    
        if(that.state === REJECTED) {
            return (promise2 = new MyPromise((resolve, reject) => {
                setTimeout(() => {
                    try {
                        const x = onRejected(that.value);
                        resolutionProcedure(promise2, x, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }
                })
            }))
            // onRejected(that.value)
        }
    
        function resolutionProcedure(promise2, x, resolve, reject) {
            // 规范规定 x 不能与 promise2 相等,这样会发生循环引用的问题
            if(promise2 === x) {
                return reject(new TypeError('Error'));
            }
    
            // 如果x 为Promise 的话,需要判断以下几个情况
            // 如果x处于等待态,Promise 需保持为等待态至 x 被执行或者拒绝
            // 如果 x 处于其他状态,则用相同的值处理Promise
            if(x instanceof MyPromise) {
                x.then(function(value) {
                    resolutionProcedure(promise2, value, resolve, reject);
                }, reject)
            }
    
            // 判断是否已经调用过函数
            let called = false;
            // 判断 x 是否为对象或者函数,如果都不是的话,将 x 传入 resolve 中
            if(x !== null && (typeof x === 'object' || typeof x === 'function')) {
                try {
                    // 如果 x 是对象或者函数的话,先把  x.then  赋值给 then, 然后再判断  then 的类型
                    let then = x.then;
                    if(typeof then === 'function') {
                        // 如果then 是函数类型的话,就将  x 作为函数的作用域  this 调用,并且传递两个回调函数作为参数,
                        // 第一个参数叫做 resolvePromise, 第二个参数为 rejectPromise, 两个回调函数都需要判断是否已经执行过函数,
                        // 然后进行相应的逻辑
                        then.call(x,
                            y => {
                                if(called) return;
                                called = true;
                                resolutionProcedure(promise2, y, resolve, reject);
                            },
                            e => {
                                if(called) return;
                                called = true;
                                reject(e);
                            }
                        )
                        // 如果不是函数类型的话,就将x传入 resolve 中
                    } else {
                        resolve(x);
                    }
                } catch (e) {
                    // 以上代码执行的过程中如果抛错了,将错误传入 reject 函数中
                    if(called) return;
                    called = true;
                    reject(e);
                }
            } else {
                resolve(x);
            }
        }
    };
    

    eg :

    new MyPromise((resolve, reject) => {
        setTimeout(() => {
            resolve(1);
        }, 0)
     }).then(value => {
        console.log(value)
     });
    

    相关文章

      网友评论

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

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