Promise A+规范解析
什么是 Promise?
Promise 是用于处理异步操作的一种机制。它表示一个异步操作的最终结果。我们主要通过其 then
方法来与 Promise 进行交互,通过注册回调函数来获取 Promise 的最终值,或者得知为什么 Promise 无法被执行的原因。
Promise A+ 规范的三个要求
Promise A+ 规范是 JavaScript 中管理异步操作的一种标准,它定义了一个符合特定要求的 Promise API。以下是 Promise A+ 规范中的三个主要要求:
-
Promise 状态:
- Promise 必须处于以下三种状态之一:pending(等待态)、fulfilled(完成态)、rejected(拒绝态)。
- 当处于 pending 状态时,可以转移到 fulfilled 或 rejected 状态,但一旦转移到其中一种状态,就不能再改变状态。
-
then 方法:
- Promise 对象必须提供一个
then
方法以访问其当前值、最终值或拒绝原因。 -
then
方法接受两个参数:onFulfilled
和onRejected
,分别是当 Promise 状态变为 fulfilled 或 rejected 时执行的回调函数。 -
then
方法必须返回一个新的 Promise 对象。
- Promise 对象必须提供一个
-
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的其它特性的实现。