手动实现完整的Promise

声明:本文是学习珠峰培训视频,模仿实现的Promise,通过了 promises-aplus-tests测试,文章最下面有截图。

const PENDING = 'pending'; // 初始态

const FULFILLED = 'fulFilled'; // 成功态

const REJECTED = 'rejected'; // 失败态

 

function Promise(exector) {

    let self = this; // 先缓存当前的 Promise实例

    self.status = PENDING; // 设置状态

    self.onResolvedCallbacks = []; // 定义存放成功回调的数组

    self.onRejectedCallbacks = []; // 定义存放失败回调的数组

 

    function resolve(value) {

        if (value instanceof Promise) {

            return value.then(resolve, reject);

        }

        //  当调用此方法的时候,如果是pending状态,则转成 成功态

        if (self.status === PENDING) {

            self.status = FULFILLED;

            self.value = value; // 成功后会得到一个值,这个值不能改

            // 调用所有成功的回调

            self.onResolvedCallbacks.forEach(cb => cb(self.value))

        }

    }

 

    function reject(reason) {

        // 如果是初始态,则转成失败态

 

        if (self.status === PENDING) {

            self.status = REJECTED;

            self.value = reason; // 失败的原因 给value

            // 调用所有失败的回调

            self.onRejectedCallbacks.forEach(cb => cb(self.value))

        }

    }

    try {

        exector(resolve, reject); // 因为此函数执行的时候,可能出异常,所以需要捕获,如果出错了,需要用错误对象Reject

    } catch (e) {

        reject(e); // 如果执行失败了,用失败的原因reject这个Promise

    }

 

}

// onFulfilled用来接收Promise成功的值或失败的原因

Promise.prototype.then = function (onFulfilled, onRejected) {

    // 如果成功和失败的回调没有传,则表示这个then没有任何逻辑,只会把值往后抛

    onFulfilled = typeof onFulfilled == 'function' ? onFulfilled : value => value;

    onRejected = typeof onRejected == 'function' ? onRejected : reason => {

        throw reason

    };

    let self = this;

    let promise2;

    // 如果当前的Promise状态已经是成功态了,onFulfilled直接取值

    if (self.status == FULFILLED) {

        return promise2 = new Promise(function (resolve, reject) {

            setTimeout(function () {

                try {

                    let x = onFulfilled(self.value)

                    // 如果获取到了返回值,会走解析Promise的过程

                    resolvePromise(promise2, x, resolve, reject);

                } catch (e) {

                    // 如果执行成功的回调中出问题了,用错误原因把promise2 reject

                    reject(e);

                }

            })

 

        })

    }

    if (self.status == REJECTED) {

        return promise2 = new Promise(function (resolve, reject) {

            setTimeout(function () {

                try {

                    let x = onRejected(self.value);

                    resolvePromise(promise2, x, resolve, reject);

                } catch (e) {

                    reject(e);

                }

            })

        })

 

    }

    if (self.status == PENDING) {

        return promise2 = new Promise(function (resolve, reject) {

            self.onResolvedCallbacks.push(function () {

                setTimeout(function () {

                    try {

                        let x = onFulfilled(self.value);

                        resolvePromise(promise2, x, resolve, reject);

                    } catch (e) {

                        reject(e);

                    }

                })

 

            })

            self.onRejectedCallbacks.push(function () {

                setTimeout(function () {

                    try {

                        let x = onRejected(self.value);

                        resolvePromise(promise2, x, resolve, reject);

                    } catch (e) {

                        reject(e);

                    }

                })

 

            })

        })

 

    }

 

    function resolvePromise(promise2, x, resolve, reject) {

        if (promise2 === x) {

            return reject(new TypeError('循环引用'));

        }

        let called = false; // 用于判断promise2是否已经resolve或reject

        // if (x instanceof Promise) {

        //     if (x.status === PENDING) {

        //         setTimeout(function () {

        //             x.then(function (y) {

        //                 resolvePromise(promise2, 2, resolve, reject)

        //             }, function (e) {

        //                 reject(e)

        //             })

        //         })

 

        //     } else {

        //         setTimeout(function () {

        //             x.then(resolve, reject);

        //         })

        //     }

        //     // x 是一个 thenable对象或函数,只要有then方法的对象    

        // } else 

        if (x != null && ((typeof x == 'object') || (typeof x === 'function'))) {

            // 以下代码 主要用于我们的Promise和别人的Promise进行交互,编写这种代码,要考虑到

            // 兼容性,允许别人出错

            try {

                let then = x.then;

                if (typeof then == 'function') {

                    // 有些promise会同时执行成功和失败的回调

                    then.call(x, function (y) {

                        // 如果promise2已经成功或者失败了,则不需要再处理了

                        if (called) return;

                        called = true;

                        resolvePromise(promise2, y, resolve, reject);

                    }, function (err) {

                        if (called) return;

                        called = true;

                        reject(err);

                    })

                } else {

                    // 如果promise2已经成功或者失败了,则不需要再处理了

                    if (called) return;

                    called = true;

                    // 到此的话 x 不是一个 thenable对象,那直接把他rosolve掉

                    resolve(x);

                }

            } catch (e) {

                if (called) return;

                called = true;

                reject(e);

            }

        } else {

            // 如果promise2已经成功或者失败了,则不需要再处理了

            if (called) return;

            called = true;

            // 如果x 是一个普通的值,就用x的值去resolve promise2

            resolve(x)

        }

 

    }

}

Promise.prototype.catch = function (onRejected) {

    // catch 的原理就是只传失败的回调

    this.then(null, onRejected);

}

Promise.deferred = Promise.defer = function () {

    let defer = {};

    defer.promise = new Promise(function (resolve, reject) {

        defer.resolve = resolve;

        defer.reject = reject;

    })

    return defer;

}

module.exports = Promise;

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章