Promise【一】

Promise A+规范解析

什么是 Promise?

Promise 是用于处理异步操作的一种机制。它表示一个异步操作的最终结果。我们主要通过其 then 方法来与 Promise 进行交互,通过注册回调函数来获取 Promise 的最终值,或者得知为什么 Promise 无法被执行的原因。

Promise A+ 规范的三个要求

Promise A+ 规范是 JavaScript 中管理异步操作的一种标准,它定义了一个符合特定要求的 Promise API。以下是 Promise A+ 规范中的三个主要要求:

  1. Promise 状态:

    • Promise 必须处于以下三种状态之一:pending(等待态)、fulfilled(完成态)、rejected(拒绝态)。
    • 当处于 pending 状态时,可以转移到 fulfilled 或 rejected 状态,但一旦转移到其中一种状态,就不能再改变状态。
  2. then 方法:

    • Promise 对象必须提供一个 then 方法以访问其当前值、最终值或拒绝原因。
    • then 方法接受两个参数:onFulfilledonRejected,分别是当 Promise 状态变为 fulfilled 或 rejected 时执行的回调函数。
    • then 方法必须返回一个新的 Promise 对象。
  3. Promise 解决程序:

    • Promise 解决程序是 Promise A+ 规范的核心算法,它定义了 Promise 对象如何处理异步操作和状态转换。
    • 在 Promise 解决程序中,如果一个 Promise 对象被 resolved(fulfilled 或 rejected),则必须按照特定的顺序执行相应的回调函数队列。
    • Promise 解决程序确保异步操作的结果能够正确传递给相应的回调函数,并且保持了回调函数的执行顺序。

遵循这三个要求可以确保 Promise 对象的行为符合预期,并且能够正确处理异步操作。

ES6 的 Promise 实现遵循了 Promise A+ 规范。


ES6 Promise 源码解析

源码地址

Promise
function Promise(fn) {
  // 判断是否通过 new 关键字调用该函数
  if (typeof this !== 'object') {
    throw new TypeError('Promises must be constructed via new');
  }
  // 判断传入的参数是否为函数
  if (typeof fn !== 'function') {
    throw new TypeError('Promise constructor\'s argument is not a function');
  }
  // 在代码中定义了多个成员变量,这些变量均以下划线 "_" 开头,并且在构建时会被简化为 _{随机数} 的格式,以达到混淆和不鼓励直接访问的目的。
  // 选择这种方式而不是使用 Symbol 或 Object.defineProperty 完全隐藏它们,是出于性能方面的考虑,因为完全隐藏可能会对性能产生影响。

  // _deferreds个数标识,0为0个,1为一个,2为多个。
  this._deferredState = 0;
  // _state有0、1、2、3四个值。
  // 0 代表pending(等待态)
  // 1 代表fulfilled(完成态)
  // 2 代表 rejected(拒绝态)
  // 3 代表采用了另外一个promise的状态
  this._state = 0;
  // 结果值
  this._value = null;
  // 采用了该promise状态的promise数组
  this._deferreds = null;
  // 在then方法中,会产生一个新的Promise对象,但新产生的对象不需要执行fn,即不需要做doResolve,这里判断直接返回即可。
  if (fn === noop) return;
  doResolve(fn, this);
}

Promise._onHandle = null;
Promise._onReject = null;
Promise._noop = noop;

// then 方法,上文提到的Promise A+规范的三个要求之一
Promise.prototype.then = function(onFulfilled, onRejected) {
  // 调用对象判断,如通过Promise.prototype.then.call(otherPromise, callback)等方式调用,需做安全调用处理。
  if (this.constructor !== Promise) {
    return safeThen(this, onFulfilled, onRejected);
  }
  // 创建一个新的Promise对象,#重点#then或catch都会产生一个新的Promise对象。
  var res = new Promise(noop);
  handle(this, new Handler(onFulfilled, onRejected, res));
  // #重点# 每调用一次then返回,返回的是一个新的Promise实例。
  return res;
};
safeThen
// 如上所述,每次调用 then 方法都会返回一个新的 Promise 对象。
// 然而,在按照 Promise A+ 规范实现的 Promise 中,直接返回 ES6 Promise 的实例是不合理的。
// 因此需要采取以下处理措施:
function safeThen(self, onFulfilled, onRejected) {
  // 通过其构造器生成一个新对象
  return new self.constructor(function (resolve, reject) {
    // 生成一个ES6 Promise对象
    var res = new Promise(noop);
    // then后调用回调
    res.then(resolve, reject);
    handle(self, new Handler(onFulfilled, onRejected, res));
  });
}
doResolve
function doResolve(fn, promise) {
  // `done`标识,确保onFulfilled(完成态回调)和onRejected(拒绝态回调)只会被调用一次
  var done = false;
  var res = tryCallTwo(fn, function (value) {
    if (done) return;
    done = true;
    resolve(promise, value);
  }, function (reason) {
    if (done) return;
    done = true;
    reject(promise, reason);
  });
  // 当`done`为`false`,并且发生异常时,执行`reject`。
  // 这种情况发生在Promise的入参`fn`在执行的时候发生异常。
  if (!done && res === IS_ERROR) {
    done = true;
    reject(promise, LAST_ERROR);
  }
}
resolve
function resolve(self, newValue) {
  // 边界场景处理,promise不能resolve自身。
  if (newValue === self) {
    return reject(
      self,
      new TypeError('A promise cannot be resolved with itself.')
    );
  }
  // 如果newValue是一个对象或者函数,需判断其是否包含then方法。
  if (
    newValue &&
    (typeof newValue === 'object' || typeof newValue === 'function')
  ) {
    var then = getThen(newValue);
    // 访问then方法异常处理
    if (then === IS_ERROR) {
      return reject(self, LAST_ERROR);
    }
    // 同根生的then时,且new Value为ES6 Promise对象时
    if (
      then === self.then &&
      newValue instanceof Promise
    ) {
      // 跟随状态(俺也一样)
      self._state = 3;
      // 新值赋给_value
      self._value = newValue;
      finale(self);
      return;
    } else if (typeof then === 'function') {
      // 如果有then方法,从新执行doResolve(不过是从头再来)
      doResolve(then.bind(newValue), self);
      return;
    }
  }
  // 状态变为完成态,newValue赋值给_value
  self._state = 1;
  self._value = newValue;
  finale(self);
}

function reject(self, newValue) {
  // 状态改为拒绝态,newValue赋值给_value
  self._state = 2;
  self._value = newValue;
  if (Promise._onReject) {
    Promise._onReject(self, newValue);
  }
  finale(self);
}
function finale(self) {
  // 调用handle,根据_deferredState判断_deferreds的个数,采用直接或遍历的调用方式,调用完清空_deferreds
  if (self._deferredState === 1) {
    handle(self, self._deferreds);
    self._deferreds = null;
  }
  if (self._deferredState === 2) {
    for (var i = 0; i < self._deferreds.length; i++) {
      handle(self, self._deferreds[i]);
    }
    self._deferreds = null;
  }
}
handle
function handle(self, deferred) {
  // 找到_state不等于3的promise(who is your daddy)
  while (self._state === 3) {
    self = self._value;
  }
  if (Promise._onHandle) {
    Promise._onHandle(self);
  }
  // 当当前对象是pending状态,将deferred赋值给对象的_deferreds。如果是多个deferred,则已数组元素的方式追加到_deferreds后。
  if (self._state === 0) {
    if (self._deferredState === 0) {
      self._deferredState = 1;
      self._deferreds = deferred;
      return;
    }
    if (self._deferredState === 1) {
      self._deferredState = 2;
      self._deferreds = [self._deferreds, deferred];
      return;
    }
    self._deferreds.push(deferred);
    return;
  }
  handleResolved(self, deferred);
}

function handleResolved(self, deferred) {
  // aspa[https://github.com/kriskowal/asap],不展开说,简单理解就是微任务。
  asap(function() {
    // 根据状态判断需要执行的回调
    var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;
    // 没有回调的情况
    if (cb === null) {
      if (self._state === 1) {
        resolve(deferred.promise, self._value);
      } else {
        reject(deferred.promise, self._value);
      }
      return;
    }
    // 执行回调
    var ret = tryCallOne(cb, self._value);
    if (ret === IS_ERROR) {
      reject(deferred.promise, LAST_ERROR);
    } else {
      resolve(deferred.promise, ret);
    }
  });
}

// Hanlder对象
function Handler(onFulfilled, onRejected, promise){
  this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
  this.onRejected = typeof onRejected === 'function' ? onRejected : null;
  this.promise = promise;
}
getThen tryCallOne tryCallTow

这几个函数是为了避免在关键函数中使用try/catch,把它们都提取到这里。

// 记录最后一次异常
var LAST_ERROR = null;
// 异常标识,使用`{}`作为值的作用类似于`Symbol`
var IS_ERROR = {};
function getThen(obj) {
  try {
    return obj.then;
  } catch (ex) {
    LAST_ERROR = ex;
    return IS_ERROR;
  }
}

function tryCallOne(fn, a) {
  try {
    return fn(a);
  } catch (ex) {
    LAST_ERROR = ex;
    return IS_ERROR;
  }
}
function tryCallTwo(fn, a, b) {
  try {
    fn(a, b);
  } catch (ex) {
    LAST_ERROR = ex;
    return IS_ERROR;
  }
}

以上是对Promise core.js的解析。后面会解析ES6 Promise的其它特性的实现。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容