2021.7.12 手撕Promise源码

根据PromiseA+规范手写Promise源码

(function () {
    "use strict";

    function Promise(executor) {
        var self = this;
        if (typeof executor !== "function") throw new TypeError("Promise resolver is not a function");
        if (!(self instanceof Promise)) throw new TypeError("undefined is not a promise");

        self.state = "pending";
        self.result = undefined;
        self.onFulfilledCallbacks = [];
        self.onRejectedCallbacks = [];
        var change = function change(state, result) {
            if (self.state !== "pending") return;
            self.state = state;
            self.result = result;
            setTimeout(function () {
                var callbacks = state === "fulfilled" ? self.onFulfilledCallbacks : self.onRejectedCallbacks;
                if (callbacks.length > 0) {
                    for (var i = 0; i < callbacks.length; i++) {
                        var item = callbacks[i];
                        if (typeof item === "function") item(self.result);
                    }
                }
            });
        };

        try {
            executor(function resolve(value) {
                change("fulfilled", value);
            }, function reject(reason) {
                change("rejected", reason);
            });
        } catch (err) {
            change('rejected', err);
        }
    }

    // 检测是否为promise实例
    var isPromise = function isPromise(x) {
        if (x !== null && /^(object|function)$/i.test(typeof x)) {
            var then;
            try {
                then = x.then;
            } catch (err) {
                return false;
            }
            if (typeof then === "function") return true;
        }
        return false;
    };

    // 严格按照PromiseA+规范处理细节
    var resolvePromise = function resolvePromise(x, promise, resolve, reject) {
        if (x === promise) throw new TypeError("Chaining cycle detected for promise #<Promise>");
        if (x !== null && /^(object|function)$/i.test(typeof x)) {
            var then;
            try {
                then = x.then;
            } catch (err) {
                reject(err);
            }
            if (typeof then === "function") {
                var called = false;
                try {
                    then.call(
                        x,
                        function onfulfilled(y) {
                            if (called) return;
                            called = true;
                            resolvePromise(y, promise, resolve, reject);
                        },
                        function onrejected(r) {
                            if (called) return;
                            called = true;
                            reject(r);
                        }
                    );
                } catch (err) {
                    if (called) return;
                    reject(err);
                }
                return;
            }
        }
        resolve(x);
    };

    // x:执行onfulfilled/onrejected的返回结果
    // promise:执行then新返回的实例
    var common = function common(callback, result, promise, resolve, reject) {
        try {
            var x = callback(result);
            resolvePromise(x, promise, resolve, reject);
        } catch (err) {
            reject(err);
        }
    };

    Promise.prototype = {
        constructor: Promise,
        then: function then(onfulfilled, onrejected) {
            var self = this,
                promise;
            if (typeof onfulfilled !== "function") {
                onfulfilled = function onfulfilled(value) {
                    return value;
                };
            }
            if (typeof onrejected !== "function") {
                onrejected = function onrejected(reason) {
                    throw reason;
                };
            }
            promise = new Promise(function (resolve, reject) {
                switch (self.state) {
                    case "fulfilled":
                        setTimeout(function () {
                            common(onfulfilled, self.result, promise, resolve, reject);
                        });
                        break;
                    case "rejected":
                        setTimeout(function () {
                            common(onrejected, self.result, promise, resolve, reject);
                        });
                        break;
                    default:
                        self.onFulfilledCallbacks.push(function (value) {
                            common(onfulfilled, value, promise, resolve, reject);
                        });
                        self.onRejectedCallbacks.push(function (reason) {
                            common(onrejected, reason, promise, resolve, reject);
                        });
                }
            });
            return promise;
        },
        // p1.catch(onrejected) => p1.then(null,onrejected)
        catch: function mycatch(onrejected) {
            return this.then(null, onrejected);
        }
    };

    Promise.resolve = function resolve(value) {
        return new Promise(function (resolve) {
            resolve(value);
        });
    };

    Promise.reject = function reject(reason) {
        return new Promise(function (_, reject) {
            reject(reason);
        });
    };

    Promise.all = function all(promises) {
        // Array.isArray
        if (!/^\[object Array\]$/i.test(Object.prototype.toString.call(promises))) throw new TypeError("promises must be an array");
        var n = 0,
            values = [];
        return new Promise(function (resolve, reject) {
            for (var i = 0; i < promises.length; i++) {
                (function (i) {
                    var promise = promises[i];
                    // 如果当前项不是promise实例,我们需要把它变为状态为成功的实例
                    if (!isPromise(promise)) promise = Promise.resolve(promise);
                    promise.then(function onfulfilled(value) {
                        // 都成功,整体实例才是成功的
                        values[i] = value;
                        n++;
                        if (n >= promises.length) resolve(values);
                    }).catch(function onrejected(reason) {
                        // 有一个是失败的,整体返回的实例就是失败的
                        reject(reason);
                    });
                })(i);
            }
        });
    };

    // 用来测试自己写的代码是否符合规范的
    Promise.deferred = function deferred() {
        var result = {};
        result.promise = new Promise(function (resolve, reject) {
            result.resolve = resolve;
            result.reject = reject;
        });
        return result;
    };

    /* 暴露API */
    if (typeof window !== "undefined") window.Promise = Promise;
    if (typeof module === "object" && typeof module.exports === "object") module.exports = Promise;
})();

手写完promise后,可以安装 promises-aplus-tests 插件进行测试

  • 配置启动命令
{
  "scripts": {
    "test": "promises-aplus-tests MyPromise.js"
  },
  ......
}
  • 开启测试
npm run test
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值