阅读 284

PromiseA+规范 - 手写Promise

课程目标

  • 了解PromiseA+规范
  • 实现一个简单的Promise

知识要点

  • Promise的三种状态
  • Promise的then方法
  • resolvePromise
  • onFulfilled和onRejected

补充知识点

PromiseA+

  1. promise 是一个有 then 方法的对象或函数
  2. thenable 是一个有 then 方法的对象或函数
  3. value 是 promise 状态成功时的值,也就是 resolve 的参数,包括各种数据类型,也包括undefined/thenable或者是 promise
  4. reason 是 promise 状态失败时的值, 也就是 reject 的参数,表示拒绝的原因
  5. exception 是一个使用throw抛出的异常值

规范

三种状态

promise有三种状态,pending、fulfilled、rejected。 其中 pending 为初始状态,fulfilled和rejected为最终态

一个 promise 被 resolve 之后变成 fulfilled 状态,必须拥有一个 value 值 一个 promise 被 rejected 之后变成 rejected 状态,必须拥有一个 reason 值

即 pending -> resolve(value) -> fulfilled

pending -> reject(reason) -> rejected

then

  Promise.then(onFulfilled, onRejected)
复制代码

promise 提供一个 then 方法用来访问最终结果,无论是 value 还是 reason

  1. 参数要求

    1.1 onFullfilled 和 onRejected 必须是函数,否则被忽略。

  2. onFulfilled 特性

    2.1 在 promise 变成 fulfilled 时,调用 onFulfilled,参数是 value

    2.2 在 promise 变成 fulfilled 之前,不应该调用

    2.3 只能调用一次

  3. onRejected 特性

    3.1 在 promise 变成 rejected 时,调用 onRejected,参数是 reason

    3.2 在 promise 变成 rejected 之前,不应该调用

    3.3 只能调用一次

  4. onFulfilled 和 onRejected 应该为微任务,用 queueMicrotask 实现。

  5. then 方法可以被调用多次

    5.1 promise状态变成 fulfilled 后,所有的 onFulfilled 回调都需要按照then的顺序执行, 也就是按照注册顺序执行

    5.2 promise状态变成 rejected 后,所有的 onRejected 回调都需要按照then的顺序执行, 也就是按照注册顺序执行

  6. 返回值

    promise2 = promise1.then(onFulfilled, onRejected)
    复制代码

    6.1 onFulfilled 或 onRejected 执行的结果为x,调用 resolvePromise

    6.2 如果 onFulfilled 或者 onRejected 执行时抛出异常,promise2需要被reject

    6.3 如果 onFulfilled 不是一个函数,promise2 以 promise1 的 value 触发fulfilled

    6.4 如果 onRejected 不是一个函数,promise2 以 promise1 的reason 触发rejected

  7. resolvePromise

    resolvePromise(promise2, x, resolve, reject)
    复制代码

    7.1 如果 promise2 和 x 相等,那么 reject TypeError

    7.2 如果 x 是一个 promsie

    x 是 pending 态,那么 promise 必须要在 pending,直到 x 变成 fulfilled or rejected.

    x 被 fulfilled, fulfill promise with the same value.

    x 被 rejected, reject promise with the same reason.

    7.3 如果 x 是一个 object 或者是一个 function

    let then = x.then
    复制代码

    x.then 这步出错,那么 reject promise with e as the reason

    then 是一个函数,then.call(x, resolvePromiseFn, rejectPromise)

    resolvePromiseFn 的 入参是 y,执行 resolvePromise(promise2, y, resolve, reject);

    rejectPromise 的 入参是 r,reject promise with r

    如果 resolvePromise 和 rejectPromise 都调用了,那么第一个调用优先,后面的调用忽略。

    如果调用then抛出异常,resolvePromise 或 rejectPromise 已经被调用,那么忽略。否则 reject promise with e as the reason

    如果 then 不是一个 function,fulfill promise with x

    代码实现

    // 定义promise类及初始状态
    const PENDING = "pending";
    const FULLFILLED = "fullfilled";
    const REJECTED = "rejected";
    
    class MyPromise {
      // 保存pending状态成功或失败的回调
      FULLFILLED_CALLBACK_LIST = [];
      REJECTED_CALLBACK_LIST = [];
      _status = PENDING;
      constructor(fn) {
        this.status = PENDING;
        this.value = null;
        this.reason = null;
        try {
          fn(this.resolve.bind(this), this.reject.bind(this));
        } catch (e) {
          this.reject(e);
        }
      }
    
      resolve(value) {
        if (this.status == PENDING) {
          this.value = value;
          this.status = FULLFILLED;
        }
      }
      reject(reason) {
        if (this.status == PENDING) {
          this.reason = reason;
          this.status = REJECTED;
        }
      }
    
      get status() {
        return this._status;
      }
      set status(newStatus) {
        this._status = newStatus;
        switch (newStatus) {
          case FULLFILLED:
            {
              this.FULLFILLED_CALLBACK_LIST.forEach((callback) => {
                callback(this.value);
              });
            }
            break;
          case REJECTED:
            {
              this.REJECTED_CALLBACK_LIST.forEach((callback) => {
                callback(this.reason);
              });
            }
            break;
        }
      }
    
      //  then接收两个参数, onFulfilled 和 onRejected
      then(onFulfilled, onRejected) {
        // 如果接收的不是function就忽略,忽略指的是原样返回 value 或者 reason.
        const realOnFulfilled = this.isFunction(onFulfilled)
          ? onFulfilled
          : (value) => {
              return value;
            };
        const realOnRejected = this.isFunction(onRejected)
          ? onRejected
          : (reason) => {
              throw reason;
            };
    
        // then 整体返回一个promise
        // 如果 onFulfilled 或者 onRejected 抛出一个异常 e ,则 promise2 必须拒绝执行,并返回拒因 e
        // 如果 onFulfilled 或者 onRejected 返回一个值 x ,则运行 resolvePromise 方法
        const promise2 = new MyPromise((resolve, reject) => {
          const fulfilledMicrotask = () => {
            try {
              const x = realOnFulfilled(this.value);
              this.resolvePromise(promise2, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          };
          const rejectedMicrotask = () => {
            try {
              const x = realOnRejected(this.reason);
              this.resolvePromise(promise2, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          };
          switch (this.status) {
            case FULLFILLED:
              fulfilledMicrotask();
              break;
            case REJECTED:
              rejectedMicrotask();
              break;
            case PENDING:
              // pending状态暂时存入数组中,等待状态改变再回调
              this.FULLFILLED_CALLBACK_LIST.push(fulfilledMicrotask);
              this.REJECTED_CALLBACK_LIST.push(rejectedMicrotask);
              break;
          }
        });
        return promise2;
      }
    
      resolvePromise(promise2, x, resolve, reject) {
        // 如果 promise2 和 x 指向同一对象,以 TypeError 为据因拒绝执行 newPromise
        if (promise2 === x) {
          return reject(
            new TypeError("The promise and the return value are the same")
          );
        }
    
        if (x instanceof MyPromise) {
          // 如果x是promise,继续执行x,如果执行的时候得到一个y,继续解析y
          queueMicrotask(() => {
            x.then((y) => {
              this.resolvePromise(promise2, y, resolve, reject);
            }, reject);
          });
        } else if (typeof x == "object" || this.isFunction(x)) {
          // 如果x是对象或函数
          if (x === null) {
            return resolve(x);
          }
          let then = null;
          try {
            then = x.then;
          } catch (e) {
            return reject(e);
          }
    
          // 如果then是函数
          if (this.isFunction(then)) {
            let called = false;
            try {
              then.call(
                x,
                (y) => {
                  if (called) return;
                  called = true;
                  this.resolvePromise(promise2, y, resolve, reject);
                },
                (r) => {
                  if (called) return;
                  called = true;
                  reject(r);
                }
              );
            } catch (e) {
              if (called) return;
              reject(e);
            }
          } else {
            resolve(x);
          }
        } else {
          resolve(x);
        }
      }
    
      // 判断是否是一个函数
      isFunction(param) {
        return typeof param === "function";
      }
    }
    复制代码
文章分类
前端
文章标签