好像有這麼一句名言——"每一個優雅的介面,背後都有一個齷齪的實現"。最明顯的例子,jQuery。之所以弄得這麼複雜,因為它本來就是那複雜。雖然有些實現相對簡明些,那是它們的相容程度去不了那個地步。當然,世上總有例外,比如mootools,但暴露到我們眼前的介面,又不知到底是那個父類的東西,結構清晰但不明撩。我之所以說這樣的話,因為非同步列隊真的很複雜,但我會儘可能讓API簡單易用。無new執行個體化,不區分執行個體與類方法,鏈式,等時髦的東西都用上。下面先奉上源碼:
;(function(){
var dom = this.dom = this.dom || {
mix : function(target, source ,override) {
var i, ride = (override === void 0) || override;
for (i in source) {
if (ride || !(i in target)) {
target[i] = source[i];
}
}
return target;
}
}
//////////////////////////////////////////////////////////////////////
//=======================非同步列隊模組===================================
var Deferred = dom.Deferred = function (fn) {
return this instanceof Deferred ? this.init(fn) : new Deferred(fn)
}
var A_slice = Array.prototype.slice;
dom.mix(Deferred, {
get:function(obj){//確保this為Deferred執行個體
return obj instanceof Deferred ? obj : new Deferred
},
ok : function (r) {//傳遞器
return r
},
ng : function (e) {//傳遞器
throw e
}
});
Deferred.prototype = {
init:function(fn){//初始化,建立兩個列隊
this._firing = [];
this._fired = [];
if(typeof fn === "function")
return this.then(fn)
return this;
},
_add:function(okng,fn){
var obj = {
ok:Deferred.ok,
ng:Deferred.ng,
arr:[]
}
if(typeof fn === "function")
obj[okng] = fn;
this._firing.push(obj);
return this;
},
then:function(fn){//_add的封裝方法1,用於添加正向回調
return Deferred.get(this)._add("ok",fn)
},
once:function(fn){//_add的封裝方法2,用於添加負向回調
return Deferred.get(this)._add("ng",fn)
},
wait:function(timeout){
var self = Deferred.get(this);
self._firing.push(~~timeout)
return self
},
_fire:function(okng,args,result){
var type = "ok",
obj = this._firing.shift();
if(obj){
this._fired.push(obj);//把執行過的回呼函數包,從一個列隊倒入另一個列隊
var self = this;
if(typeof obj === "number"){//如果是延時操作
var timeoutID = setTimeout(function(){
self._fire(okng,self.before(args,result))
},obj)
this.onabort = function(){
clearTimeout(timeoutID );
}
}else if(obj.arr.length){//如果是並行操作
var i = 0, d;