乐趣区

关于前端:如何实现Promise-的实例方法和静态方法

Promise 是异步编程的一种解决方案,比传统的回调函数或事件更正当和更灵便。本文次要展现 Promise 提供的办法列表,以及根本的实现原理。通过本文,咱们能加深 Promise 办法的了解和场景应用,对 Promise.all、Promise.race、Promise.allSettled 和 Promise.any 四个办法的异同之处也有更深层次的领悟。一、Promise 办法列表
Promise 的实例办法有 then/catch/finally 三种,静态方法有 all/race/allSettled/any/resolve/reject 六种。其中 then 实现起来因为波及 Promise 裁决过程(The Promise Resolution Procedure),会比较复杂,其余的都是基于已有性能的拓展。上面都给大伙列出所有的办法。Promise.prototype.then()
Promise.prototype.catch()
Promise.prototype.finally()
Promise.all()
Promise.race)
Promise.allSettled)
Promise.any()
Promise.resolve()
Promise.reject()
二、Promise 九种办法实现
1. 原型办法 then
then 办法是整个 Promise 解决的核心内容,同时因为回调函数和返回一个新的 Promise 实例,因而决定过程比较复杂。// class MyPromise {
//     static PENDING = 'pending'; // 进行中
//     static FULFILLED = 'fulfilled'; // 已胜利
//     static REJECTED = 'rejected'; // 已失败
//     state = MyPromise.PENDING;
//     value = null;
//     reason = null;
//     onFulfilledCallbacks = [];
//     onRejectedCallbacks = [];
//     ...
// }
MyPromise.prototype.then = (onFulfilled, onRejected) => {if (typeof onFulfilled != 'function') {onFulfilled = (value) => value;
  }
  if (typeof onRejected != 'function') {onRejected = (reason) => {throw reason;};
  }
  // Promise 外围解决过程 见标准 2.3
  const _resolvePromise = (promise, x, resolve, reject) => {
    // 2.3.1 如果 promise 和 x 指向同一对象,抛出 TypeError 谬误
    if (promise === x) {
      const errMsg = 'The promise and the return value are the same';
      return reject(new TypeError(errMsg));
    }

    // 2.3.3 如果 x 为对象(不是 null)或者函数
    if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
      let then = null;
      try {
        // 2.3.3.1. 检索属性 x.then
        then = x.then;
      } catch (error) {
        // 2.3.3.2 如果 x.then 导致抛出异样 e,则以 e 为回绝起因回绝 promis
        return reject(error);
      }

      // 2.3.3.3 如果 then 是一个函数,x 作为 then 的 this 调用该办法,第一个参数是胜利的回调函数,第二个参数是失败的回调函数
      if (typeof then === 'function') {
        let called = false;
        try {
          then.call(
            x,
            (y) => {
              // 2.3.3.3.4 如果胜利回调与失败回调都被调用或屡次调用同一个参数,则第一个调用优先,其余调用都将被疏忽。if (called) return;
              called = true;
              // 2.3.3.3.1 如果胜利回调以值 y 调用,运行 [[Resolve]](promise,y)
              _resolvePromise(promise, y, resolve, reject);
            },
            (r) => {
              // 2.3.3.3.4 如果胜利回调与失败回调都被调用或屡次调用同一个参数,则第一个调用优先,其余调用都将被疏忽。if (called) return;
              called = true;
              // 2.3.3.3.2 如果失败回调以起因 r 调用,用 r 回绝 promise
              reject(r);
            }
          );
        } catch (error) {
          // 2.3.3.4 如果调用 then 办法抛出异样 e:
          // 2.3.3.4.1 若胜利回调或失败回调都调用过,疏忽
          if (called) return;

          // 2.3.3.4.2 未调用,用 e 作为起因回绝 promise
          reject(error);
        }
      } else {
        // 2.3.3.4. 如果 then 不是函数,用 x 作为值实现 promise
        return resolve(x);
      }
    } else {
      // 2.3.4 如果 x 不为对象或者函数,以 x 为参数执行 promise
      return resolve(x);
    }
  };
  // 链式返回的 Promise
  const newPromise = new MyPromise((resolve, reject) => {switch (this.state) {
      case MyPromise.FULFILLED:
        setTimeout(() => {
          try {const x = onFulfilled(this.value);
            _resolvePromise(newPromise, x, resolve, reject);
          } catch (reason) {reject(reason);
          }
        }, 0);
        break;
      case MyPromise.REJECTED:
        setTimeout(() => {
          try {const x = onRejected(this.reason);
            _resolvePromise(newPromise, x, resolve, reject);
          } catch (reason) {reject(reason);
          }
        }, 0);
        break;
      case MyPromise.PENDING:
        this.onFulfilledCallbacks.push(() => {setTimeout(() => {
            try {const x = onFulfilled(this.value);
              _resolvePromise(newPromise, x, resolve, reject);
            } catch (reason) {reject(reason);
            }
          }, 0);
        });
        this.onRejectedCallbacks.push(() => {setTimeout(() => {
            try {const x = onRejected(this.reason);
              _resolvePromise(newPromise, x, resolve, reject);
            } catch (reason) {reject(reason);
            }
          }, 0);
        });
        break;
    }
  });
  return newPromise;
};
2. 原型办法 catch
如果下面没有定义 reject 办法或者在抛出谬误,那么所有的异样会走向 catch 办法,而 catch 能够复用 then 办法。MyPromise.prototype.catch = function (onRejected) {return this.then(null, onRejected);
};
3. 原型办法 finally
不论是 resolve 还是 reject 都会调用 finally。那么相当于 fianlly 办法替使用者别离调用了一次 then 的 resolved 和 rejected 状态回调。MyPromise.prototype.finally = function (fn) {
  return this.then((value) => {fn();
      return value;
    },
    (reason) => {fn();
      throw reason;
    }
  );
};
4. 静态方法 Promise.all
Promise.all() 办法用于将多个 Promise 实例,包装成一个新的 Promise 实例。所有参数数组 Promise 实例执行 resolve 回调后,新实例执行 resolve 回调;如果两头有任何一个 Promise 实例执行 reject 回调,那么新实例就间接执行 reject 回调了。打个比方:多名员工别离同时进行多个我的项目,你要求任何一个我的项目都必须是令你称心的,有一个不称心都算这件事(所有我的项目)是失败的。强调的是整体令你称心。MyPromise.all = function (promises) {return new Promise((resolve, reject) => {if (promises.length === 0) {resolve([]);
    } else {let result = [];
      let index = 0;
      for (let i = 0; i < promises.length; i++) {promises[i].then((data) => {result[i] = data;
            if (++index === promises.length) {resolve(result);
            }
          },
          (err) => {reject(err);
            return;
          }
        );
      }
    }
  });
};
5. 静态方法 Promise.race
Promise.race() 顾名思义,就是比赛,返回最快实现那一个 Promise 实例。只有参数数组中有一个 Promise 实例执行 resolve 回调或 reject 回调后,新实例就间接返回后果。打个比方:多名员工别离同时进行多个我的项目,你只有最快实现的我的项目,无论我的项目是否令你称心。强调的是要快。MyPromise.race = function (promises) {return new Promise((resolve, reject) => {if (promises.length === 0) {resolve();
    } else {
      let index = 0;
      for (let i = 0; i < promises.length; i++) {promises[i].then((data) => {resolve(data);
          },
          (err) => {reject(err);
            return;
          }
        );
      }
    }
  });
};
6. 静态方法 Promise.allSettled
Promise.allSettled() 办法只有等到参数数组的所有 Promise 实例都产生状态变更,返回的 Promise 实例才会产生状态变更,无论是执行 resolve 回调还是 reject 回调的状态。打个比方:多名员工别离同时进行多个我的项目,你要求每个一个我的项目都必须实现,而后失去所有我的项目是令你称心还是令你不称心的。强调的是最终后果。MyPromise.allSettled = function (promises) {return new Promise((resolve, reject) => {if (promises.length === 0) {resolve([]);
    } else {let result = [];
      let index = 0;
      for (let i = 0; i < promises.length; i++) {promises[i]
          .then((value) => {result[i] = {
                status: 'fulfilled',
                value,
              };
            },
            (reason) => {result[i] = {
                status: 'rejected',
                reason,
              };
            }
          )
          .finally(() => {if (++index === promises.length) {return resolve(result);
            }
          });
      }
    }
  });
};
同时因为 Promise.allSettled() 和 Promise.all() 都是对所有 Promise 实例的一种解决,上面就能够利用 Promise.all() 来实现 Promise.allSettled() 办法。MyPromise.allSettled = function (promises) {
  return Promise.all(promises.map((item) =>
      Promise.resolve(item).then((value) => ({status: 'fulfilled', value}),
        (reason) => ({status: 'rejected', reason})
      )
    )
  );
};
7. 静态方法 Promise.any
Promise.any() 办法是返回任意一个最快执行 resolve 回调的 Promise 实例。打个比方:多名员工同时进行多个我的项目,你只有最快失去令你称心的那个我的项目,无论所有我的项目最终都没令你称心,这件事(所有我的项目)才算是失败了。强调的是又快又好。MyPromise.any = function (promises) {return new Promise((resolve, reject) => {if (promises.length === 0) {return resolve();
    } else {let result = [];
      let index = 0;
      for (let i = 0; i < promises.length; i++) {promises[i].then((value) => {return resolve(value);
          },
          (reason) => {result[i] = reason;
            if (++index === promises.length) {return reject(new AggregateError(result));
            }
          }
        );
      }
    }
  });
};
8. 静态方法 Promise.resolve
Promise.resolve 办法返回一个以给定值解析后的 Promise 实例。相当于执行 then 办法外面的 _resolvePromise。MyPromise.reject = function (value) {return new MyPromise((resolve, reject) => {resolve(value);
  });
};
9. 静态方法 Promise.reject
Promise.reject 办法返回一个带有回绝起因的 Promise 实例。MyPromise.reject = function (reason) {return new MyPromise((resolve, reject) => {reject(reason);
  });
};
退出移动版