这篇文章可以看作是屈屈同学关于when.js的文章《异步编程:When.js快速上手》的续篇。
屈屈的文章中详细介绍了when.js,在这里关于when.js的使用我就不多复述了,大家可以自己去研究它的API。
在这里,我主要想讨论的是如何实现一个when.js类似的promise/A框架。为了更清晰了解实现原理,我略过when.js中一些比较强大的功能,只实现其中最核心的功能,包括基本的then(),otherwise()以及比较好用的all()和any()。
下面看一下Promise的基本数据结构:
function Promise(){
this._resolves = [];
this._rejects = [];
this._readyState = Promise.PENDING;
this._data = null;
this._reason = null;
}
mix(Promise, {
PENDING : 0,
FULFILLED : 1,
REJECTED : 2,
isPromise: function(obj){
return obj != null && typeof obj['then'] == 'function';
}
});
我们可以看到,一个Promise包含五个属性,一个resolves数组用来存放当状态转换为FULFILLED之时需要执行的动作,rejects数组用来存放当状态转换为REJECTED时需要执行的动作,一个readyState属性用来存放当前的Promise对象的状态,一个data属性用来存放调用resolve时传递参数,一个_reason属性用来存放调用reject时传递的参数。
详细的参数说明我们继续看后面的实现会比较明白:
mix(Promise.prototype, {
then: function(onFulfilled, onRejected){
var deferred = new Defer();
function fulfill(data){
var ret = onFulfilled ? onFulfilled(data) : data;
if(Promise.isPromise(ret)){
ret.then(function(data){
deferred.resolve(data);
});
}else{
deferred.resolve(ret);
}
return ret;
}
if(this._readyState === Promise.PENDING){
this._resolves.push(fulfill);
if(onRejected){
this._rejects.push(onRejected);
}else{
//为了让reject向后传递
this._rejects.push(function(reason){
deferred.reject(reason);
});
}
}else if(this._readyState === Promise.FULFILLED){
var self = this;
setTimeout(function(){
fulfill(self._data);
});
}
return deferred.promise;
},
otherwise: function(onRejected){
return this.then(undefined, onRejected);
}
});
Promise.prototype.then 是整个组件里面最复杂的地方,代码直接阅读可能看起来会比较不明白,我后面会详细讲,在这里先暂时把这个方法做一个简化,便于大家理解其中最核心的内容:
mix(Promise.prototype, {
then: function(onFulfilled, onRejected){
if(this._readyState === Promise.PENDING){
if(onFulfilled){
this._resolves.push(onFulfilled);
}
if(onRejected){
this._rejects.push(onRejected);
}
}else if