A promise library in ES6 for learning Promise/A+ Specification.
- 模仿了Adehun的实现
- 通过了promises-aplus-tests所有测试用例
npm install & npm run test在实现过程中,参考Promise/A+规范,我们把Promise抽象成以下模块。
then方法是规范中定义的方法,同时也应该是Promise最重要的标识,主要特点如下:
- then方法接受两个可选参数: onFulfilled, onRejected
- then方法必须返回一个promise
then(onFulfilled, onRejected) {
const queuedPromise = new Lamb();
if (Utils.isFunction(onFulfilled)) {
queuedPromise.handlers.onFulfilled = onFulfilled;
}
if (Utils.isFunction(onRejected)) {
queuedPromise.handlers.onRejected = onRejected;
}
this.queue.push(queuedPromise);
this.process();
return queuedPromise;
}transition方法检查promise当前state的合法性并更新其state和value,并将接下来的处理交给process方法。
transition(state, value) {
if (this.state === state || this.state !== VALIDATE_STATE.PENDING || !Utils.isValidateState(state) ||
arguments.length !== 2) {
return;
}
this.state = state;
this.value = value;
this.process();
}- 我们知道当一个promise(姑且将这个promise叫做
base promise)的then方法执行时,then方法创建的新的promise(queuedPromise)会被push到base promise的pending queue中。 - transiton方法执行后,
base promise的state和value更新 - then方法执行后,
base promise的pending queuepush 新的queuedPromise - process方法会在then方法和transition方法中被调用,处理后续流程。
process() {
if (this.state === VALIDATE_STATE.PENDING) {
return;
}
const that = this;
// 2.2.4 onFulfilled or onRejected must not be called until the execution context stack contains only platform code.
Utils.runAsync(() => {
while (that.queue && that.queue.length) {
const queuedPromise = that.queue.shift();
let handler = null;
let value = null;
if (that.state === VALIDATE_STATE.FULFILLED) {
handler = queuedPromise.handlers.onFulfilled || Utils.defaultFulfillCallback;
} else if (that.state === VALIDATE_STATE.REJECTED) {
handler = queuedPromise.handlers.onRejected || Utils.defaultRejectCallback;
}
try {
value = handler(that.value);
} catch (e) {
queuedPromise.transition(VALIDATE_STATE.REJECTED, e);
continue;
}
resolve(queuedPromise, value);
}
});
}Process runs the Promise Resolution procedure on all internally stored promises (i.e. those that were attached to the base promise through the then function) and enforces the following Promise/A+
resolve可能是promise最核心的模块,它处理promise的“解决”(resolve)过程。依照Promise/A+规范的定义,resolve方法的形式为: [[Resolve]](promise, x)。
const resolve = (x) => {
if (x === this) {
// 当需要resolve的x是当前promise的时候,直接reject,并抛出TypeError异常
promise.transition(VALIDATE_STATE.REJECTED, new TypeError('The promise and its value refer to the same object.'));
} else if (Utils.isPromise(x)) {
// 当x的类型是promise且非当前promise时,根据x的state进行相应处理
if (x.state === VALIDATE_STATE.PENDING) {
// 若x的state为pending时,当前promise的resolve被延迟
x.then(value => resolve(this, value), reason => this.transition(VALIDATE_STATE.REJECTED, reason));
} else {
// 若x的state为fulfilled或者rejected,则使用x的state和value应用于当前promise
this.transition(x.state, x.value);
}
} else if (Utils.isObject(x) || Utils.isFunction(x)) {
// 若x的类型为Ojbect或者function时(thenable),检查该对象上是否有then方法
let then = null;
let isCalled = false;
try {
then = x.then;
if (Utils.isFunction(then)) {
then.call(x, (value) => {
if (!isCalled) {
resolve(this, value);
isCalled = true;
}
}, (reason) => {
if (!isCalled) {
this.reject(reason);
isCalled = true;
}
});
} else {
this.fulfill(x);
isCalled = true;
}
} catch (e) {
if (!isCalled) {
this.reject(e);
isCalled = true;
}
}
} else {
this.fulfill(x);
}
};- 根据Promis/A+规范Promise有3个状态:
PENDING,FULFILLED(settled),REJECTED(settled)。 - 处于
FULFILLED和REJECTED状态的promise,其状态不能再进行转移。
const VALIDATE_STATE = {
PENDING: 0,
FULFILLED: 1,
REJECTED: 2,
};
const Utils = {
// 异步执行帮助函数
runAsync: (fn) => {
setTimeout(fn, 0);
},
// 判断一个值是否是promise类型
isPromise: p => p && p instanceof Lamb,
// 判断一个值是否是对象类型
isObject: value => value && typeof value === 'object',
// 判断一个值是否是函数类型
isFunction: value => value && typeof value === 'function',
// 默认的`fulfill`函数
defaultFulfillCallback: value => value,
// 默认的`reject`函数
defaultRejectCallback: (reason) => { throw reason; },
// 判断一个状态是否是合法的promise状态
isValidateState: state => (state === VALIDATE_STATE.PENDING) || (state === VALIDATE_STATE.FULFILLED) ||
(state || VALIDATE_STATE.REJECTED),
};fulfill和reject分别会将当前promise的状态转移到settled(fulfilled or rejected)状态,并交由transition方法进行后续处理
reject(reason) {
this.transition(VALIDATE_STATE.REJECTED, reason);
}
fulfill(value) {
this.transition(VALIDATE_STATE.FULFILLED, value);
}