zoukankan      html  css  js  c++  java
  • 手写 Promise

    一、前言

    Promise 的手写也算是经典的前端题目了,这得要求你对 Promise 非常了解才可以。
    Promise 详情的 API 请点这里,这里我简单讲下两个静态方法:

    • Promise.reject():返回一个以给定值解析后的Promise 对象
    • Promise.resolve():返回一个带有拒绝原因的Promise对象

    还有一件事就是,Promise 是自己带有状态的,共计三种:pendingfulfilledrejected
    Promise 刚开始创建时,状态为pending。一旦你的 Promise 执行了 resolve 或者 reject 回调,那么 Promise 后续状态只能为fulfilledrejected的其中一种。
    注意 Promise 的原型方法:

    • Promise.prototype.then():有两个参数,第一个处理fulfilled状态,第二个处理rejected状态
    • Promise.prototype.catch():有一个参数,只处理rejected状态
    • Promise.prototype.finally():有一个参数,无论fulfilled还是rejected,都会执行;finally() 经过测试,可以放在 then() 或者 catch() 之前,后面的 then() 或者 catch() 还是会执行。也就是说,finally() 并不会终止后续的处理,并且可以多次设置。

    在 Promise 的处理链中(即 then()、catch() 、finally() 组成的链式调用),这有个小例子:

    let example=new Promise();
    example.then().catch().finally().then().finally(); 
    // 这个就是 Promise 的处理链,pending 状态结束后,处理链会依照顺序依次调用 then() 或者 catch() 或者 finally()
    // 举个例子,如果 Promise 状态为 fulfilled,处理到 catch() 时会跳过,进入下一个处理,此时的 catch() 便会失效 
    // catch() 能传入两个参数,能处理 fulfilled 状态或者 rejected 状态
    // finally() 无论 Promise 是那种状态,当处理到这个位置上时都会执行,但是回调函数没有参数
    

    二、代码实现

    const PENDING = "pending";          // Promise 执行状态
    const FULFUILLED = "fulfuilled";    // Promise 完成状态
    const REJECTED = "rejected";        // Promise 失败状态
    class MyPromise {
        __state = PENDING;  // 状态
        __callbacks = [];   // 回调数组,完成或者失败将要调用的
        __value = null;     // 正确的值
        __reason = null;    // 拒绝的值
    
        static resolve(arg) {
            return new MyPromise(resolve => {
                resolve(arg);
            })
        }
    
        static reject(arg) {
            return new MyPromise((_, reject) => {
                reject(arg);
            });
        }
    
        constructor(callBack) {
            try {
                callBack((arg) => {
                    this.__value = arg;
                    this.__state = FULFUILLED;
                    this.__main();
                }, (arg) => {
                    this.__reason = arg;
                    this.__state = REJECTED;
                    this.__main();
                });
            } catch (e) {
                this.__reason = e;
                this.__state = REJECTED;
                this.__main();
            }
        }
    
        __mainIsRunning = false;
        __main() {
            // 确保 MyPromise 的主体方法只能被执行一次
            if(this.__mainIsRunning){
                return;
            }
            this.__mainIsRunning=true;
            // 异步处理,同时也是为了 then、catch、finally 能够将函数组册进入 __callbacks
            setTimeout(() => {
                for (let callBack of this.__callbacks) {
                    const func = callBack[this.__state];
                    func && func();
                }
                if (this.__state === REJECTED) {
                    console.error("未捕捉的错误(in MyPromise)", this.__reason);
                }
            })
        }
    
        /**
         * 回调函数包装工厂
         * 根据 FULFUILLED 或者 REJECTED 状态,使用传入的回调函数进行处理
         * @param {Function} func 注册的回调函数
         * @param {"fulfuilled"|"rejected"} state 状态
         * @returns 
         */
        __callbackFactory(func, state) {
            return () => {
                if (typeof func === "function") {
                    try {
                        const ans = func(state === FULFUILLED ? this.__value : this.__reason);
                        // 函数返回结果为 MyPromise 类型, 那么将其状态转移到正在运行的 MyPromise 主体
                        if (ans instanceof MyPromise) {
                            this.__state = ans.__state;
                            if (this.__state === FULFUILLED) {
                                this.__value = ans.__value;
                            } else {
                                // 如果返回的 MyPromise 的状态为 REJECTED,必须重置其为 FULFUILLED,不然会自动在控制台报错
                                // 原因是 MyPromise.prototype.__main()
                                ans.__state = FULFUILLED;
                                this.__reason = ans.__reason;
                            }
                        } else {
                            // 如果函数返回结果不是 MyPromise,那么状态必定为 FULFUILLED
                            this.__value = ans;
                            this.__state = FULFUILLED;
                        }
                    } catch (e) {
                        // 捕捉回调函数运行中的错误,此时状态为REJECTED
                        this.__reason = e;
                        this.__state = REJECTED;
                    }
                }
            }
        }
    
        then(fullfilledCallback, rejectedCallback) {
            const callback = {
                [FULFUILLED]: this.__callbackFactory(fullfilledCallback, FULFUILLED),
                [REJECTED]: this.__callbackFactory(rejectedCallback, REJECTED),
            }
            this.__callbacks.push(callback);
            return this;
        }
    
        catch (rejectedCallback) {
            const callback = {
                [FULFUILLED]: null,
                [REJECTED]: this.__callbackFactory(rejectedCallback, REJECTED),
            }
            this.__callbacks.push(callback);
            return this;
        };
    
        finally(finnallycallBack) {
            finnallycallBack = typeof finnallycallBack === "function" ? finnallycallBack : null;
            const callback = {
                [FULFUILLED]: finnallycallBack,
                [REJECTED]: finnallycallBack,
            }
            this.__callbacks.push(callback);
            return this;
        }
    }
    
    
    

    三、效果

        // 原生测试
        new Promise((resolve, reject) => {
            setTimeout(() => reject(1), 1000);
        }).then((res) => {
            console.log("原生测试 then(1):", res);
            return Promise.reject(res + 1);
        }, res => {
            console.log("原生测试 cath(1):", res);
            return Promise.reject(res + 1);
        }).catch(res => {
            console.log("原生测试 catch(2):", res);
            return Promise.resolve(res + 1);
        }).finally((res) => {
            console.log("原生测试 finally(1):", res)
        }).finally((res) => {
            console.log("原生测试 finally(2):", res)
        }).then(res => {
            console.log("原生测试 then(3):", res);
            return Promise.reject()
        }).finally(() => {
            console.log("原生测试 finally(4):原生Promise测试结束!");
        })
    
        // 自定义测试
        new MyPromise((resolve, reject) => {
            setTimeout(() => reject(1), 1000);
        }).then((res) => {
            console.log("自定义测试 then(1):", res);
            return MyPromise.reject(res + 1);
        }, res => {
            console.log("自定义测试 cath(1):", res);
            return MyPromise.reject(res + 1);
        }).catch(res => {
            console.log("自定义测试 catch(2):", res);
            return MyPromise.resolve(res + 1);
        }).finally((res) => {
            console.log("自定义测试 finally(1):", res)
        }).finally((res) => {
            console.log("自定义测试 finally(2):", res)
        }).then(res => {
            console.log("自定义测试 then(3):", res);
            return MyPromise.reject()
        }).finally(() => {
            console.log("自定义测试 finally(4):自定义Promise测试结束!");
        })
    

    效果图:

    四、总结

    手写的 Promise 用的定时器开始运行,当然优先级不如原生 Promise,毕竟 Promise 完成后是 micro task。
    Promise 手写不难,还有就是 Promise 其他的静态方法现实其实是最简单的。
    关键点:

    • 创建 Promise 的过程中,传入的回调函数是马上执行的,不会在事件循环中执行,且resolve、reject不会终止该回调的执行
    • Promise 自身拥有状态;
    • Promise 自身拥有对 rejected 状态或者 fulfilled 状态的状态数据保存,我的代码中 rejected 状态是用变量 __reason 保存,fulfilled 状态是用变量 __value 保存的;
    • Promise pending 状态结束后,就没有 pending 状态了,只有 fulfilled 或者 rejected 状态 。Promise.reject()、Promise.resolve() 是已经指定了fulfilled 或者 rejected 状态。
  • 相关阅读:
    Python内置函数(49)——isinstance
    Python内置函数(48)——__import__
    Python内置函数(47)——vars
    Python内置函数(46)——format
    Python内置函数(45)——ascii
    Python内置函数(44)——len
    Python内置函数(43)——type
    Python内置函数(42)——hash
    Python内置函数(41)——id
    Linux下redis常用命令
  • 原文地址:https://www.cnblogs.com/panshaojun/p/15305155.html
Copyright © 2011-2022 走看看