手写实现Promise-构造器

108 阅读2分钟

手写Promise-构造器的实现

// 提出变量,减少hard code
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";

class MyPromise {
    // 私有属性,外部不能使用 | ES6 Symbol
    #state = PENDING;
    #result = undefined;
    #handlers = [];

    constructor(executor) {
        const resolve = (data) => {
            // Promise状态一旦确定不可更改
            this.#changeState(FULFILLED, data);
        };

        const reject = (reason) => {
            this.#changeState(REJECTED, reason);
        };

        // 只能捕获同步报错,异步错误不会影响Promise状态
        // 多有面试题考查
        try {
            // 执行器,进入会立即执行
            executor(resolve, reject);
        } catch (err) {
            reject(err);
        }
    }

    // 提炼重复代码
    #changeState(state, result) {
        if (this.#state !== PENDING) return;
        this.#state = state;
        this.#result = result;
        this.#run();
    }

// 什么时候调用resolve,什么时候调用reject
// 对应的回调不是函数,比如null、undefined等
// 回调是函数
// 返回的结果是Promise

// 穿透:传入的不是一个回调,那么then返回的Promise就跟之前调用的(p1)一致

    
    // 判断是否是Promise,满足Promise A+规范(此处关键)
    #isPromiseLike(value) {
        if (
            value !== null &&
            (typeof value === "object") | (typeof value === "function")
        ) {
            return typeof value.then === "function";
        }
        return false;
    }
    
    // Promise需要放到微队列中执行 
    // 区分环境
    #runMicroTask(func) {
        // node环境
        if (typeof process === "object" && typeof process.nextTick === "function") {
            process.nextTick(func);
        } else if (typeof MutationObserver === "function") {
            // 浏览器环境
            const ob = new MutationObserver(func);
            const textNode = document.createTextNode("1");
            ob.observe(textNode, { characterData: true });
            textNode.data = "2";
        } else {
            setTimeout(func, 0);
        }
    }

    #runOne(callback, resolve, reject) {   
        this.#runMicroTask(() => {
            // 判断回调函数是否是函数
            if (typeof callback !== "function") {
                const settled = this.#state === FULFILLED ? resolve : reject;
                settled(this.#result);
                return;
            } else {
                try {
                    const data = callback(this.#result);
                    if (this.#isPromiseLike(data)) {
                        data.then(resolve, reject);
                    } else {
                        resolve(data);
                    }
                } catch (error) {
                    reject(error);
                }
            }
        });
    }

    #run() {
        if (this.#state === PENDING) return;
        while (this.#handlers.length) {
            const { onFulfilled, onRejected, resolve, reject } =
            this.#handlers.shift();
            if (this.#state === FULFILLED) {
            this.#runOne(onFulfilled, resolve, reject);
            } else {
            this.#runOne(onRejected, resolve, reject);
            }
        }
    }

    // then方法需要解决两件事,第一是确定传入的两个回调(成功和失败)什么时候运行
    // 第二then方法要返回一个Promise,这个Promise什么时候完成,什么时候失败
    then(onFulfilled, onRejected) {
        return new MyPromise((resolve, reject) => {
            // 通过数组是因为可能会多次调用
            this.#handlers.push({
                onFulfilled,
                onRejected,
                resolve,
                reject,
            });
            this.#run();
        });
    }
    
    // ES6 封装的Promise
    catch(onRejected) {
        return this.then(undefined, onRejected);
    }
    
    finally(onFinally) {
        return this.then(
        (data) => {
            onFinally();
            return data;
        },
        (err) => {
            onFinally();
            throw err;
        }
    );
}

    static resolve(value) {
        // 判断原型,如果该值为一个 Promise 对象,则返回该对象
        if (value instanceof MyPromise) return value;

        // 静态方法里不能调用实例方法,所以需要创建变量保存
        let _resolve, _reject;
        const p = new MyPromise((resolve, reject) => {
            _resolve = resolve;
            _reject = reject;
        });
        if (p.#isPromiseLike(value)) {
            value.then(_resolve, _reject);
            } else {
            _resolve(value);
        }
        return p;
    }

    static reject(reason) {
        return new MyPromise((resolve, reject) => {
            reject(reason);
        });
    }
}

总结补充

  1. MDN Promise文档 developer.mozilla.org/zh-CN/docs/…
  2. Dry原则:Don't repeat yourself。优化代码,提炼出重复代码
  3. 事件循环是环境能力,不是语言能力