返回

轻量级前端Promise库 Promiz 精妙解析

前端

前言

在上一篇文章[译]前端基础知识储备——Promise/A+规范中,我们介绍了Promise/A+规范的具体条目。在本文中,我们选择了一个具体的Promise库——Promiz,让大家来看一下它的内部代码是如何运作的。Promiz是一个体积很小的Promise库(官方介绍约为913字节),但它功能齐全,符合Promise/A+规范。

Promiz源代码解析

Promiz的源代码非常简单,只有不到100行代码。我们一起来看一下它的源代码:

(function (global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  typeof define === 'function' && define.amd ? define(factory) :
  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Promiz = factory());
}(this, (function () { 'use strict';

  /**
   * @description 创建一个新的Promise实例
   * @param {Function} executor 执行器函数
   */
  function Promiz(executor) {
    if (typeof executor !== 'function') {
      throw new TypeError('executor must be a function');
    }

    // Promise状态,初始为pending
    this.status = 'pending';
    // Promise结果值
    this.value = undefined;
    // Promise拒绝原因
    this.reason = undefined;
    // 存储成功回调函数的数组
    this.onFulfilledCallbacks = [];
    // 存储失败回调函数的数组
    this.onRejectedCallbacks = [];

    // 执行器函数,立即执行
    try {
      executor(resolve.bind(this), reject.bind(this));
    } catch (error) {
      reject.call(this, error);
    }
  }

  /**
   * @description 将Promise状态改为fulfilled,并执行成功回调函数
   * @param {*} value Promise结果值
   */
  function resolve(value) {
    if (this.status !== 'pending') {
      return;
    }

    this.status = 'fulfilled';
    this.value = value;

    // 执行成功回调函数
    this.onFulfilledCallbacks.forEach(function (callback) {
      callback(value);
    });
  }

  /**
   * @description 将Promise状态改为rejected,并执行失败回调函数
   * @param {*} reason Promise拒绝原因
   */
  function reject(reason) {
    if (this.status !== 'pending') {
      return;
    }

    this.status = 'rejected';
    this.reason = reason;

    // 执行失败回调函数
    this.onRejectedCallbacks.forEach(function (callback) {
      callback(reason);
    });
  }

  /**
   * @description 添加成功回调函数
   * @param {Function} callback 成功回调函数
   * @returns {Promiz} 返回当前Promise实例
   */
  Promiz.prototype.then = function (onFulfilled, onRejected) {
    var self = this;

    // 返回一个新的Promise实例
    return new Promiz(function (resolve, reject) {
      // 将成功回调函数添加到数组中
      self.onFulfilledCallbacks.push(function (value) {
        // 如果成功回调函数不为null,则执行该函数
        if (typeof onFulfilled === 'function') {
          try {
            // 将成功回调函数的返回值作为新Promise的结果值
            var result = onFulfilled(value);
            // 如果返回值是Promise,则将该Promise的最终结果作为新Promise的结果值
            if (result instanceof Promiz) {
              result.then(resolve, reject);
            } else {
              resolve(result);
            }
          } catch (error) {
            reject(error);
          }
        } else {
          // 如果成功回调函数为null,则将Promise结果值作为新Promise的结果值
          resolve(value);
        }
      });

      // 将失败回调函数添加到数组中
      self.onRejectedCallbacks.push(function (reason) {
        // 如果失败回调函数不为null,则执行该函数
        if (typeof onRejected === 'function') {
          try {
            // 将失败回调函数的返回值作为新Promise的结果值
            var result = onRejected(reason);
            // 如果返回值是Promise,则将该Promise的最终结果作为新Promise的结果值
            if (result instanceof Promiz) {
              result.then(resolve, reject);
            } else {
              resolve(result);
            }
          } catch (error) {
            reject(error);
          }
        } else {
          // 如果失败回调函数为null,则将Promise拒绝原因作为新Promise的拒绝原因
          reject(reason);
        }
      });
    });
  };

  /**
   * @description 添加失败回调函数
   * @param {Function} callback 失败回调函数
   * @returns {Promiz} 返回当前Promise实例
   */
  Promiz.prototype.catch = function (onRejected) {
    return this.then(null, onRejected);
  };

  /**
   * @description 添加finally回调函数
   * @param {Function} callback finally回调函数
   * @returns {Promiz} 返回当前Promise实例
   */
  Promiz.prototype.finally = function (callback) {
    return this.then(function (value) {
      return Promiz.resolve(callback()).then(function () {
        return value;
      });
    }, function (reason) {
      return Promiz.resolve(callback()).then(function () {
        throw reason;
      });
    });
  };

  /**
   * @description 创建一个成功状态的Promise实例
   * @param {*} value Promise结果值
   * @returns {Promiz} 返回一个新的Promise实例
   */
  Promiz.resolve = function (value) {
    return new Promiz(function (resolve) {
      resolve(value);
    });
  };

  /**
   * @description 创建一个失败状态的Promise实例
   * @param {*} reason Promise拒绝原因
   * @returns {Promiz} 返回一个新的Promise实例
   */
  Promiz.reject = function (reason) {
    return new Promiz(function (resolve, reject) {
      reject(reason);
    });
  };

  /**
   * @description 判断一个值是否为Promise实例
   * @param {*} value 要判断的值
   * @returns {boolean} 如果是Promise实例,则返回true,否则返回false
   */
  Promiz.isPromiz = function (value) {
    return value instanceof Promiz;
  };

  /**
   * @description 执行所有Promise实例的then方法,并将结果收集到一个数组中
   * @param {Array} promises Promise实例数组
   * @returns {Promiz} 返回一个新的Promise实例,该实例的结果值是所有Promise实例结果值的数组
   */
  Promiz.all = function (promises) {
    return new Promiz(function (resolve, reject) {
      var result = [];
      var count = 0;

      promises.forEach(function (promise, index) {
        promise.then(function (value) {
          result[index] = value;
          count++;

          if (count === promises.length) {
            resolve(result);
          }
        }, function (reason) {
          reject(reason);
        });
      });
    });
  };

  /**
   * @description 执行所有Promise实例的then方法,并将第一个结果值作为新Promise的结果值
   * @param {Array} promises Promise实例数组
   * @returns {Promiz} 返回一个新的Promise实例,该实例的结果值是第一个Promise实例的结果值
   */
  Promiz.race = function (promises) {
    return new Promiz(function (resolve, reject) {
      promises.forEach(function (promise) {
        promise.then(resolve, reject);
      });
    });
  };

  return Promiz;

})));

从上面的源代码中,我们可以看到Promiz的实现非常简单,它主要包括以下几个部分:

  • 构造函数Promiz :用于创建新的Promise实例。
  • resolve方法 :将Promise状态改为fulfilled,并执行成功回调函数。
  • reject方法 :将Promise状态改为rejected,并执行失败回调函数。
  • then方法