JS进阶-手写Promise

一、什么是Promise

在Promise A+规范中规定,Promise是一个有一个符合规范的then方法的对象或者函数。

1.关于then

  • then接收onFulfilled和onRejected两个可选参数;
  • then必须返回一个新的Promise对象;
  • 如果onFulfilled是一个函数
    • 在状态切换为fulfilled之后调用;
    • 不能被多次调用。
  • 如果onRejected是一个函数
    • 在状态切换为rejected是被调用;
    • 不能被多次调用。

2.状态

  • pending: 初始状态,会转换为下面的俩个状态;
  • fulfilled: 成功状态,不会再转为其他状态;
  • rejected: 失败状态,不会再转为其他状态。

3.关于ES6中的Promise

  • 构造函数接受一个回调函数executor;
  • executor接受两个参数resolve、reject;
  • executor在new Promise是被同步调用;
  • 任务被解决时,调用resolve,并传入结果;
  • 任务被拒绝时,调用reject,并传入拒绝原因;
  • Promise对象除了then还有catch和finally两个函数;
  • Promise有all、resolve等静态函数。

二、实现

1.状态定义

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

2.功能实现

class MyPromise {
    // 当前状态
    #state = PENDING;
    // 解决或拒绝的结果
    #result = undefined;
    // 通关连环then注册的回调
    #handlers = [];

    // 构造函数
    constructor(executor) {
        // 定义两个状态切换函数
        const resolve = (data) => {
            this.#setState(FULFILLED, data);
        };
        const reject = (reason) => {
            this.#setState(REJECTED, reason);
        };
        // 同步调用参数函数
        try {
            executor(resolve, reject);
        } catch (error) {
            reject(error);
        }
    }

    // 状态切换
    #setState(state, result) {
        if (this.#state !== PENDING) return;
        this.#state = state;
        this.#result = result;
        this.#run();
    }
    
    // 执行then注册的所有任务
    #run() {
        if (this.#state === PENDING) return;
        // 遍历所有注册的回调
        while(this.#handlers.length > 0){
            const handler = this.#handlers.shift();
            const {resolve, reject, onFulfilled, onRejected} = handler;
            // 根据结果执行每个任务
            if (this.#state === FULFILLED) {
                this.#runOne(onFulfilled, resolve, reject);
            } else if (this.#state === REJECTED) {
                this.#runOne(onRejected, resolve, reject);
            }
        }
    }

    // 执行一个任务
    #runOne() {
        // 将任务放入微队列,等待被执行
        this.#runMicroTask(() => {
            if (typeof callback !== 'function') {
                // 不是函数的话,透传一下当前结果
                if (this.#state === FULFILLED) {
                    resolve(this.#result);
                } else {
                    reject(this.#result);
                }
                return;
            }
            try {
                const data = callback(this.#result);
                if (this.#isPromiseLike(data)) {
                    // 结果是Priomise的话
                    data.then(resolve, reject);
                } else {
                    // 不是Promise的话直接完成,并传递结果
                    resolve(data);
                }
            } catch (error) {
                reject(error);
            }
        });
    }

    // 按Promise A+规范判断参数是否是一个Promise
    #isPromiseLike(value) {
        if (value !== null && (typeof value === 'object' || typeof value === 'function')) {
            return typeof value.then === 'function';
        }
        return false;
    }

    // 将任务放入微队列
    #runMicroTask(func) {
        if (typeof process === 'object' && typeof process.nextTick === 'function') {
            // 在nodejs中
            process.nextTick(func);
        } else if (typeof MutationObserver === 'function') {
            // 在浏览器中
            const textNode = document.createTextNode('1');
            const ob = new MutationObserver(func);
            // 让ob观察textNode的字符串变化,观察到之后会将构造函数
            // 中传入的func加入微队列执行
            ob.observe(textNode, {
                characterData: true,
            });
            textNode.data = '2';
        } else {
            // 没有上述环境,只能用宏队列代替了
            setTimeout(func, 0);
        }
    }

    then(onFulfilled, onRejected) {
        // 返回新Promise
        return new MyPromise((resolve, reject) => {
            // 将任务存起来
            this.#handlers.push({
                resolve,
                reject,
                onFulfilled,
                onRejected,
            });
            this.#run();
        });
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值