手写简单版 Promise

176 阅读2分钟

前言

  • 不针对 Promise A+ 规范实现。
  • 不考虑异步,因为要实现的话需要基于 generator,比较复杂。
  • 只针对在某个现实场景中需要手写,所以会简化,不使用太复杂的方式去实现,能满足简单功能。
  • 因为目的不是真的要你写个大而全 Promise,只是要在有限的时间里检验你的代码功底和对 Promise 的了解。

当我们在做题的时候,特别是面对一个边界比较模糊的问题,需要对解决问题的结果具象化,首先我们先拟定,我们要实现 Promise 的如下功能。

MyPromise.resolve(1).then((res) => {
  return 1 + res
}).then((res) => {
  console.log(res)
})
// 输出 2

const p = new MyPromise((resolve, reject) => {
    resolve(1)
}).then((res) => {
  console.log(res)
    throw 'error'
}).catch((e) => {
  console.log(e)
})
// 先输出 1,再输出 error

  • 那么我们接下来的解法可以如下:
class MyPromise {
    // 留意构造函数是接收一个函数,函数的两个参数函数是实参,留意不要写错
    constructor(cb) {
        // 注意有 3 中状态用来判断接下来 then 和 catch 的执行
        this.states = {
            PENDING: 'PENDING',
            RESOLVED: 'RESOLVED',
            REJECTED: 'REJECTED'
        }

        // 默认开始的状态为 pending
        this.state = this.states.PENDING;

        // 用来做 then catch 之间的 value 的扭转
        this.value = null;

        // 对 cb 回调函数的两个实参的实现
        const resolve = (val) => {
            this.value = val;
            this.state = this.states.RESOLVED;
        }

        const reject = (val) => {
            this.value = val;
            this.state = this.states.REJECTED;
        }

        // 注意,在执行 cb 回调的时候,也要去捕获错误,满足就需要更改状态
        try {
            cb(resolve, reject);
        } catch (e) {
            reject(e)
        }
    }

    // 注意 resolve 和 reject 是两个静态函数,但是要接 then 所有要返回一个实例
    static resolve(val) {
        const promise = new MyPromise((res) => res(val))
        promise.value = val;
        promise.state = promise.states.RESOLVED;
        return promise;
    }

    static reject(val) {
        const promise = new MyPromise((res, rej) => rej(val))
        promise.value = val;
        promise.state = promise.states.REJECTED;
        return promise;
    }

    // then 有两个参数,分别对应 resolve 和 reject 的回调,注意判断两个函数的执行条件
    then(resFn, rejFn) {
        // 需要捕获错误
        try {
            // 是函数且状态不是被 reject
            if (typeof resFn === 'function' && this.state !== this.states.REJECTED) {
                // 留意这里因为下一次 then 的 value 是上一次 then 返回的值,故需要做此操作
                this.value = resFn(this.value)
            }
            // 假如有错误,直接进入到 reject 状态
        } catch (e) {
            this.state = this.states.REJECTED;
            this.value = e;
            return this;
        }

        // 同理
        if (typeof rejFn === 'function' && this.state === this.states.REJECTED) {
            this.state = this.states.REJECTED;
            this.value = rejFn(this.value)
        }

        return this;
    }

    // catch 仅当被 reject 的时候返回
    catch(cb) {
        if (this.state === this.states.REJECTED) {
                this.value = cb(this.value)
        }
        return this;
    }
}