本文代码实现 Promise/A+ 规范
首先
首先当然要定义一些 Promise 要用到的状态变量和垫片函数:
// 定义 Promise 状态
const PENDING = 0;
const REJECTED = -1;
const FULFILLED = 1;
// 用于创建空的 Promise 对象
const NOOP = function () {};
// 2.2.4 notes#3.1
// 用于异步调用 onFulfilled & onRejected
var asyncCall = (process && process.nextTick) ||
setImmediate ||
function (callback) {
if (typeof callback !== 'function')
throw new TypeError('callback is not a function');
setTimeout(callback, 0);
};
接下来就是标准式的构造函数了:
function Promise (excutor) {
if (!(this instanceof Promise)) {
return new Promise(excutor);
}
if (typeof excutor !== 'function') {
throw new TypeError('Promise executor is not a function');
}
// 初始化 pending 状态
this._state = PENDING;
// value & reason of Promise
this._value = null;
this._reason = null;
// 在被 fulfill 或 reject 之前,
// 保留对回调函数 onFulfilled 和 onRejected 的引用
this._subscribers = [];
var promise = this;
try {
excutor(function (value) {
//todo: resolve `promise` with value
__resolve__(promise, value);
}, function (reason) {
//todo: reject `promise` with reason
__reject__(promise, reason);
})
} catch (exception) {
//todo: reject `promise` with `exception` as reason
__reject__(promise, exception);
}
}
fulfill & reject
Promise 只可能由 pending 向 fulfilled 或 rejected 两种状态之一转化且不可逆转。
分别定义函数 fulfill(promise, value)
和 reject(promise, reason)
来完成这一过程:
(为了避免和其他函数中的同名参数引起混淆,我就直接采用前后加两个下划线的方式命名了)
function __fulfill__(promise, value) {
// 先做状态检查
if (promise._state === PENDING) {
// 改变 `promise` 的状态
promise._state = FULFILLED;
promise._value = value;
// 依次调用已绑定的回调函数
var subscribers = promise._subscribers;
for (var i = 0; i < subscribers.length; ++i) {
//todo: 此处应调用 onFulfilled
invokeCallback(promise, subscibers[i]);
}
}
}
function __reject__(promise, reason) {
// 状态检查
if (promise._state === PENDING) {
// 改变 `promise` 的状态
promise._state = REJECTED;
promise._reason = reason;
// 依次调用已绑定回调函数
var subscribers = promise._subscribers;
for (var i = 0; i < subscribers.length; ++i) {
//todo: 此处应调用 onRejected
invokeCallback(promise, subscribers[i]);
}
}
}
Promise 的解析过程(Promise Resolution Procedure)
估计不少同学已经发现了,通常我们写 Promise 的时候通常会把 excutor
函数的参数命名为 resolve
和 reject
而不是 fulfill
和 reject
。因为实际上 resolve 和 fulfill 并不是相同的过程,此处引用下规范中的原文:
The promise resolution procedure is an abstract operation taking as input a promise and a value, which we denote as
[[Resolve]](promise, x)
. Ifx
is a thenable, it attempts to make promise adopt the state ofx
, under the assumption thatx
behaves at least somewhat like a promise. Otherwise, it fulfillspromise
with the valuex
.
当使用一个值 x
去 resolve 一个 promise 的时候,会先判断 x
是否是一个 thenable
(promise 对象和类 promise 对象),如果是则尝试使 promise 的状态与该 thenable
保持一致;如果不是则直接用 x
fulfill 这个 promise。
总结来说 resolve 一个 promise 。promise 可能变成 fulfilled 也可能变成 rejected。那么接下来按照规范,依葫芦画瓢地实现这一过程。
function __resolve__(promise, x) {
// 2.3.1
if (promise === x)
return __reject__(promise,
new TypeError('try to resolve a promise with itself'));
// 2.3.2 如果 `x` 是一个 Promise 对象,
// 使 `promise` 和 `x` 的状态保持一致
if (x instanceof Promise) {
if (x._state === PENDING) {
x.then(function (v) {
__resolve__(promise, v);
}, function (r) {
__reject__(promise, r);
});
} else if (x._state === FULFILLED) {
__resolve__(promise, x._value);
} else {
__reject__(promise, x._reason);
}
return;
}
var type = typeof x;
//!!! 注意此处 typeof null 结果会是 'object'
if ((type === 'object' && x !== null) || type === 'function') {
// 检查该对象或函数是否为 thenable
handleThenable(promise, x);
} else {
// 2.3.4 其他类型的值直接 fulfill
__fulfill__(promise, x);
}
}
// 2.3.3
function handleThenable(promise, x) {
var then = null; // 取值 `x.then`
// 标记 resolvePromise 或 rejectPromise 其一是否被调用过
//!!! 不可缺少,[[resolve]] 过程不能保证立即使 "promise" 的状态发生变化
var isCalled = false;
try {
then = x.then;
if (typeof then === 'function') {
try {
then.call(x, function resolvePromise(v) {
if (isCalled) return;
__resolve__(promise, v);
isCalled = true;
}, function rejectPromise(r) {
if (isCalled) return;
__reject__(promise, r);
isCalled = true;
});
} catch (e1) {
if (!isCalled) {
__reject__(promise, e1);
}
// 如果 resolvePromise 或 rejectPromise
// 已被调用,忽略该异常
}
}
// 2.3.3.4 不是 thenable
else {
__fulfill__(promise, x);
}
} catch (e2) {
// 2.3.3.2
__reject__(promise, e2);
}
}
then 方法的实现
规范规定,promise 的 then 方法可以被多次调用,每次调用都会返回一个 promise 对象。在回调函数被正式调用前我们需要保持对新的 promise 的引用,建立一个 { promise2, onFulfilled, onRejected } 三元组用于记录回调函数和 promise 对应关系。
// { promise2, onFulfilled, onRejected } 三元组
function Triad(promise, onFulfilled, onRejected) {
if (!(this instanceof Triad)) {
return new Triad(promise, onFulfilled, onRejected);
}
this._promise = promise;
// 2.2.1 当 onFulfilled 和 onRejected 不是函数时将会被忽略
// 2.2.5 onFulfilled 和 onRejected 必须以函数的形式调用
this._onFulfilled = typeof onFulfilled === 'function'
? onFulfilled.bind(undefined)
: null;
this._onRejected = typeof onRejected === 'function'
? onRejected.bind(undefined) :
: null;
}
Promise.prototype.then = function (onFulfilled, onRejected) {
// then 方法必须返回一个新的 promise
var promise2 = new Promise(NOOP);
var triad = new Triad(promise2, onFulfilled, onRejected);
if (this._state === PENDING) {
// pending,直接将三元组加入订阅队列,保证顺序!
this._subscribers.push(triad);
} else {
// 已经 fulfilled 或 rejected 就直接(异步)执行回调函数
invokeCallback(this, triad);
}
return promise2;
}
invokeCallback
/* 根据 promise 的状态,执行三元组中的回调函数 */
function invokeCallback(promise, triad) {
var state = promise._state;
var value = promise._value;
var reason = promise._reason;
var promise2 = triad._promise;
var onFulfilled = triad._onFulfilled;
var onRejected = triad._onRejected;
if (state === FULFILLED) {
if (onFulfilled) {
asyncCall(function() {
try {
__resolve__(promise2, onFulfilled(value));
} catch (e) {
__reject__(promise2, e);
}
});
} else {
__fulfill__(promise2, value);
}
} else if (state === REJECTED) {
if (onRejected) {
asyncCall(function () {
try {
__resolve__(promise2, onRejected(reason));
} catch (e) {
__reject__(promise2, e);
}
});
} else {
__reject__(promise2, reason);
}
}
}