Introduction
本文最初来源于 Stack Overflow的一个回答,探讨如同使用javascript实现一个promise,你也能通过阅读本文更深入的理解promise的实现机制。
State Machine
因为promise是一个状态机,因而我们可以先考虑之后会用到哪些状态信息。
var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;
function Promise() {
// store state which can be PENDING, FULFILLED or REJECTED
var state = PENDING;
// store value or error once FULFILLED or REJECTED
var value = null;
// store sucess & failure handlers attached by calling .then or .done
var handlers = [];
}
Transitions
然后在考虑两个重要的状态变化, fulfilling 和rejecting
var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;
function Promise() {
// store state which can be PENDING, FULFILLED or REJECTED
var state = PENDING;
// store value once FULFILLED or REJECTED
var value = null;
// store sucess & failure handlers
var handlers = [];
function fulfill(result) {
state = FULFILLED;
value = result;
}
function reject(error) {
state = REJECTED;
value = error;
}
}
这段代码是一个基础的状态变化,之外还有其他的更加高级的状态变化叫做resolve
var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;
function Promise() {
// store state which can be PENDING, FULFILLED or REJECTED
var state = PENDING;
// store value once FULFILLED or REJECTED
var value = null;
// store sucess & failure handlers
var handlers = [];
function fulfill(result) {
state = FULFILLED;
value = result;
}
function reject(error) {
state = REJECTED;
value = error;
}
function resolve(result) {
try {
var then = getThen(result);
if (then) {
doResolve(then.bind(result), resolve, reject)
return
}
fulfill(result);
} catch (e) {
reject(e);
}
}
}
这里resolve接受promise和一个普通值,如果是个promise,需要执行这个promise。A promise must never be fulfilled with another promise, so it is this resolve function that we will expose, rather than the internal fulfill. We've used a couple of helper methods, so lets define those:
/**
* Check if a value is a Promise and, if it is,
* return the `then` method of that promise.
*
* @param {Promise|Any} value
* @return {Function|Null}
*/
function getThen(value) {
var t = typeof value;
if (value && (t === 'object' || t === 'function')) {
var then = value.then;
if (typeof then === 'function') {
return then;
}
}
return null;
}
/**
* Take a potentially misbehaving resolver function and make sure
* onFulfilled and onRejected are only called once.
*
* Makes no guarantees about asynchrony.
*
* @param {Function} fn A resolver function that may not be trusted
* @param {Function} onFulfilled
* @param {Function} onRejected
*/
function doResolve(fn, onFulfilled, onRejected) {
var done = false;
try {
fn(function (value) {
if (done) return
done = true
onFulfilled(value)
}, function (reason) {
if (done) return
done = true
onRejected(reason)
})
} catch (ex) {
if (done) return
done = true
onRejected(ex)
}
}
Constructing
我们现在有了完整的内部状态机, 但我们还没有一个处理promise或观察它的方法。让我们开始添加resolve方法。
var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;
function Promise(fn) {
// store state which can be PENDING, FULFILLED or REJECTED
var state = PENDING;
// store value once FULFILLED or REJECTED
var value = null;
// store sucess & failure handlers
var handlers = [];
function fulfill(result) {
state = FULFILLED;
value = result;
}
function reject(error) {
state = REJECTED;
value = error;
}
function resolve(result) {
try {
var then = getThen(result);
if (then) {
doResolve(then.bind(result), resolve, reject)
return
}
fulfill(result);
} catch (e) {
reject(e);
}
}
doResolve(fn, resolve, reject);
}
如你所见,这里多次调用doResolve,因为调用实在不同的resolve上面发生的,fn可以多次调用resolve和reject,甚至抛出异常,必须确保promise只能resolved或者reject一次,then也不能转变成之前的状态。
Observing (via .done)
现在已经完成了这个状态机,但是仍旧缺乏手段观察到内部的变化,我们最终的目标是实现then,但是done要更加好些,因而首先来实现done。
.done需要实现的功能
- 只有当onFulfilled或者onRejected发生时
- 只能被调用一次
- 直到下一次调用(即在返回方法返回后)才调用它。
- 确保在resilve之前或者之后done都要被调用
var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;
function Promise(fn) {
// store state which can be PENDING, FULFILLED or REJECTED
var state = PENDING;
// store value once FULFILLED or REJECTED
var value = null;
// store sucess & failure handlers
var handlers = [];
function fulfill(result) {
state = FULFILLED;
value = result;
handlers.forEach(handle);
handlers = null;
}
function reject(error) {
state = REJECTED;
value = error;
handlers.forEach(handle);
handlers = null;
}
function resolve(result) {
try {
var then = getThen(result);
if (then) {
doResolve(then.bind(result), resolve, reject)
return
}
fulfill(result);
} catch (e) {
reject(e);
}
}
function handle(handler) {
if (state === PENDING) {
handlers.push(handler);
} else {
if (state === FULFILLED &&
typeof handler.onFulfilled === 'function') {
handler.onFulfilled(value);
}
if (state === REJECTED &&
typeof handler.onRejected === 'function') {
handler.onRejected(value);
}
}
}
this.done = function (onFulfilled, onRejected) {
// ensure we are always asynchronous
setTimeout(function () {
handle({
onFulfilled: onFulfilled,
onRejected: onRejected
});
}, 0);
}
doResolve(fn, resolve, reject);
}
确保当Promise resolved 或者rejected时 handlers 能够执行而不是等到下一个next tick
Observing (via .then)
现在已经完成了done,那么可以用同样的方式实现then,区别在于重新构造一个新的Promise
this.then = function (onFulfilled, onRejected) {
var self = this;
return new Promise(function (resolve, reject) {
return self.done(function (result) {
if (typeof onFulfilled === 'function') {
try {
return resolve(onFulfilled(result));
} catch (ex) {
return reject(ex);
}
} else {
return resolve(result);
}
}, function (error) {
if (typeof onRejected === 'function') {
try {
return resolve(onRejected(error));
} catch (ex) {
return reject(ex);
}
} else {
return reject(error);
}
});
});
}