jQuery在1.5引入了Deferred对象(异步列队),当时它还没有划分为一个模块,放到核心模块中。直到1.52才分割出来。它拥有三个方法:_Deferred, Deferred与when。
出于变量在不同作用域的共用,jQuery实现异步列队时不使用面向对象方式,它把_Deferred当作一个工厂方法,返回一个不透明的函数列队。之所以说不透明,是因为它的状态与元素都以闭包手段保护起来,只能通过列队对象提供的方法进行操作。这几个方法分别是done(添加函数),resolveWith(指定作用域地执行所有函数),resolve(执行所有函数),isResolved(判定是否已经调用过resolveWith或resolve方法),cancel(中断执行操作)。但_Deferred自始至终都作为一个内部方法,从没有在文档中公开过。
Deferred在1.5是两个_Deferred的合体,但1+1不等于2,它还是做了增强。偷偷爆料,Deferred本来是python世界大名鼎鼎的Twisted框架的东西,由早期七大JS类库中的MochiKit取经回来,最后被dojo继承衣钵。jQuery之所以这样构造Deferred,分明不愿背抄袭的恶名,于是方法改得一塌糊涂,是jQuery命名最差的API,完全不知所云。它还加入当时正在热烈讨论的promise机制。下面是一个比较列表:
jQuery的when方法用於實現回調的回調,或者說,幾個異列列隊都執行後才執行另外的一些回調。這些後來的回調也是用done, when, fail加的,但when回傳的這個物件已經加入讓使用者控制它執行的能力了。因為這時它是種叫Promise的東西,只負責增加回呼與讓使用者窺探其狀態。一旦前一段回呼都觸發了,它就自然進入正常回調列隊(deferred ,見Deferred方法的定義)或錯誤回調列隊(failDeferred )中去。不過我這樣講,對於沒有非同步程式設計經驗的人來說,一定聽得雲裡霧裡。看實例好了。
jQuery.extend({
queue: function( elem, type, data ) {
if ( !elem ) {
return;
}
type = (type || "fx") "queue";
var q = jQuery.data( elem, type ); // 如果只是查找,則可以快速出隊
if ( !data ) {
return q
}
if ( !q || jQuery.isArray(data) ) {
q = jQuery.data( elem, type, jQuery.makeArray( data) );
} else {
q.push(
}
回傳q;
},
出隊: function( elem, type ) {
type = type || "fx";
var queue = jQuery.queue( elem, type ), fn = queue.shift(); // 如果fx 隊列出隊,則始終移除進度哨兵
if ( fn === "inprogress" ) {
fn = queue.shift();
if ( fn ) {
// 增加進度哨兵以防止fx 隊列
// 自動出隊
if ( type === "fx" ) {
queue.unshift("inprogress");
}
fn.call(elem, function( ) {
jQuery.dequeue(elem, type)
});
jQuery .fn.extend({
queue: function( type, data ) {
if ( typeof type !== "string" ) {
data = type;
type = " fx";
}
if ( data === undefined ) {
return jQuery.queue( this[0], type );
}
return this.each(function( i , elem ) {
var queue = jQuery.queue( this, type, data );
if ( type === "fx" && queue[0] !== "inprogress" ) {
jQuery .dequeue(this this , type );
}
});
出隊: function( type ) {
return this.each(function() {
jQuery. dequeue( this, type );
});
// 基於Clint Helfers 的插件,經許可。 php/2009/07/jquery-delay/
延遲:函數( time, type ) {
time = jQuery.fx ? jQuery.fx.speeds[time] || time : time;類型|| "fx ";
回傳this.queue( type, function() {
var elem = this;
setTimeout(function() {
jQuery.dequeue( elem, type );
},時間);
});
clearQueue: function( type ) {
return this.queue( type || "fx", [] ); >}
});
1.6 增加了_mark,_unmark,promise。 queue 是讓函數同屬一個隊伍裡面,目的是讓動畫一個接一個執行。 _mark 頂讓他們各自擁有隊伍,並列執行(雖然其中只記錄非同步列隊中已被執行的函數個數)。 promise則在這些並發執行的動畫執行後才執行另外一些回呼(或動畫)。
複製程式碼
程式碼如下:
(function( jQuery ) {
function handleQueueMarkDefer( elem, type, src ) {
//清空記錄deferredvar個數的隊字段,函數列隊與異步列
type "defer",
queueDataKey = type "queue",
markDataKey = type "mark",
defer = jQuery.data( elem, deferDataKey, undefined, true );
if ( defer &&
( src === "queue" || !jQuery.data( elem, queueDataKey, undefined, true ) ) &&
( src === "mark" || !jQuery.data( elem, markDataKey, undefined , true ) ) ) {
// 為硬編碼回調提供空間,以便先觸發
// 並最終在元素上標記/排隊其他內容
setTimeout( function() {
if 。 );
}
}, 0
}
}
jQuery.extend({
_mark: function( elem, type ) {
if ( elem ) {
type = (type || "fx") "mark";//建立一個以mark為後綴的字段,用於記錄此列隊中的個數
jQuery.data( elem, type, (jQuery.data (elem,類型,未定義,true) || 0) 1, 正確);
}
},
_unmark: function(force, elem, type ) {
if (force != = true ) {
type = elem;
elem = 力;
力=假;
}
if ( elem ) {
type = type || “fx”;
var key = type "mark",
//讓個數減1,如果第一個參數為true,就強逼減至0
count = force ? 0 : ( (jQuery.data( elem , key, 未定義, true) || 1 ) - 1 );
if ( count ) {
jQuery.data( elem, key, count, true );
} else {//如果為0,就移除它
jQuery.removeData( elem, key, true );
handleQueueMarkDefer( elem, type, "mark" );
}
}
},
},
隊列: function( elem, type, data ) {
if ( elem ) {
type = (type || "fx") "queue 」;
var q = jQuery.data( elem, type, undefined, true );
// 如果這只是一個查找,則透過快速退出來加速出隊
if ( data ) {
if ( !q || jQuery.isArray(data) ) {
q = jQuery.資料( elem, 類型, jQuery.makeArray(data), true );
} else {
q.push( 資料);
}
}
回傳q || [];
}
},
出隊: function( elem, type ) {
type = type || “fx”;
var queue = jQuery.queue( elem, type ),
fn = queue.shift(),
defer;
// 如果fx 隊伍列出隊,總是刪除進度標記
if ( fn === "inprogress" ) {
fn = queue.shift();
}
if ( fn ) {
// 增加進度哨兵,防止fx 佇列被
// 自動出列
if ( type === "fx" ) {
queue.unshift("進行中");
}
fn.call(elem, function() {
jQuery.dequeue(elem, type );
});
}
if ( !queue.length ) {
jQuery.removeData( elem, type "queue", true );
handleQueueMarkDefer( elem, type, " queue" );
}
}
});
jQuery.fn.extend({
queue: function( type, data ) {
if ( typeof type !== "string" ) {
data = type;
type = " fx";
}
if ( data === undefined ) {
return jQuery.queue( this[0], type );
}
return this.each(function() {
var queue = jQuery.queue( this, type, data );
if ( type === "fx" && queue [0] !== "inprogress" ) {
jQuery.dequeue(這個,類型);
}
});
出隊:函數( type ) {
回傳this. each(function() {
jQuery.dequeue( this , type );
},
// 基於Clint Helfers 的插件,經許可。 /07/jquery-delay/
延遲:函數( time, type ) {
time = jQuery.fx ? jQuery.fx.speeds[time] || time : time; "fx";
return this.queue( type, function() {
var elem = this;
setTimeout(function() {
jQuery.dequeue( elem, type );
}, 時間);
},
clearQueue: function( type ) {
return this.queue( type || "fx",
},
//把jQuery 物件裝進一個非同步列隊,允許它在一步列隊,允許它在一步列隊系列動畫中再執行之後綁定的回呼
promise: function( type, object ) {
if ( typeof type !== "字串" ) {
物件= 類型;
類型=未定義;
}
類型= 類型|| “fx”;
var defer = jQuery.Deferred(),
elements = this,
i = elements.length,
count = 1,
deferDataKey = type "defer",
queueDataKey =輸入“佇列”,
markDataKey = 輸入“標記”;
函數resolve() {
if ( !( - -count ) ) {
defer.resolveWith( elements, [ elements ] );
}
}
while( i-- ) {
//如果之前已經使用過unmark、queue等方法,那麼我們將產生一個新的延遲感測器硬碟系統
if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) ||
( jQuery.data( elements[ i ],queueDataKey, undefined, true ) ||
jQuery.data( elements[ i ], markDataKey, undefined, true ) ) &&
jQuery.data( elements[ i ], deferData, jQuery._Deferred( true ) )) {
count ;
tmp.done( 解決);
}
}
resolve();
回傳defer.promise();
}
});
})( jQuery );
jQuery.ajax模組也被染指,$.XHR對象,當作HTTPXMLRequest對象的仿造器是由一個Deferred對象與一個_Deferred的對象構成。
deferred = jferred.Deferred( = jQuery._Deferred(),
jqXHR ={/**/}
//....
deferred.promise( jqXHR );
jqXHR.success = jqXHR.done;
jqXHR.error = jqXHR.fail;
jqXHR.complete = completeDeferred.done;
jQuery1.7,從deferred模組中分化出callback模組,其實就是先前的_Deferred的增強版,新增去重,鎖定,return false時中斷執行下一個回調,清空等功能。
複製程式碼 程式碼如下:
(function( jQuery ) {
// 字串到物件標誌格式快取
var flagsCache = {};
// 將字串格式的標誌轉換為物件格式的標誌並且儲存在快取
function createFlags( flags ) {
var object = flagsCache[ flags ] = {},
i, length;
flags = flags.split( /s / ) i = 0, length = flags.length; i
object[ flags[i] ] = true;
傳回物件;
* 使用下列參數建立回呼清單:
*
* 標誌:以空格分隔的標誌的可選列表,將更改
* 回調列表的行為方式
*
* 預設情況下,回調列表將像事件回調列表一樣,並且可以
*“觸發”多次
*
* 可能的標誌:
*
*一次:將確保回呼列表只能被觸發一次(如延遲)
*
* 內存:將跟踪以前的值,並在列表立即觸發後調用任何添加的回調
* 最新的“記憶”
*值(如延遲)
*
*唯一:將確保回調只能添加一次(清單中沒有重複)
*
* stopOnFalse:中斷呼叫當回調回傳false
*
*/
jQuery.Callbacks = function( flags ) {
// 將標誌從字串格式轉換為物件格式
// (我們簽入先快取)
flags = flags ? ( flagsCache[ 標誌] || createFlags( 標誌) ) : {};
var // 實際回呼列表
list = [],
// 可重複列表的fire 呼叫堆疊
stack = [],
// 最後的fire 值(用於不可忘記的) list)
memory,
// 標記以了解清單目前是否正在觸發
firing,
// 第一個觸發回調(由add 和fireWith 內部使用)
firingStart,
// 觸發時循環結束
firingLength,
// 目前觸發回調的索引(如果需要,可透過刪除進行修改)
firingIndex,
// 將一個或多個回調加入清單
add = function( args ) {
var i,
長度,
elem,
類型,
實際;
for ( i = 0, length = args.length; i
for ( i = 0, length = args.length; i elem = args[ i ];
type = jQuery.type( elem );
if ( type === "array" ) {
// 遞歸檢查
add( elem );
} else if ( type === "function" ) {
// 增加if 不是唯一模式且回呼不在
if ( !flags.unique || !self.has ( elem ) ) {
list.push( elem );
}
}
}
},
// 觸發回呼
fire = function( context, args ) {
args = args || [];
內存= !flags.內存|| [上下文,參數];
開火= true;
fireingIndex = fireStart || 0;
點火開始= 0;
fireingLength = list.length;
for ( ; list &&fireingIndex if (list[fireingIndex].apply( context, args ) = flagsse & flags ) = flags, args ) = flagse & flags ) = flags args ) = flags ) stopOnFalse ) {
內存= true; // 標記為停止
break;
}
}
開火= false;
if ( list ) {
if ( !flags>if ( !flags>if ( !flags>if !flags .once ) {
if ( stack && stack.length ) {
內存= stack.shift();
self.fireWith( 內存[ 0 ], 內存[ 1 ] );
}
} else if (內存=== true ) {
self.disable();
} else {
list = [];
}
}
},
// 實際回呼物件
self = {
// 將回呼或回呼集合新增至清單
add: function( ) {
if ( list ) {
var length = list .length;
新增(參數);
// 我們是否需要將回調新增至
// 目前觸發批次?
if (fireing) {
firingLength = list.length;
// 有了內存,如果我們沒有開火,那麼
// 我們應該立即調用,除非之前的
//開火被停止(stopOnFalse)
} else if ( memory && memory ! == true ) {
firingStart = 長度;
火(記憶體[0],記憶體[1]);
}
火(記憶體[0],記憶體[1]);
}
火(記憶體[0],記憶體[1]); 🎜>}
傳回此;
},
// 從清單中刪除回呼
remove: function() {
if (list ) {
var args = arguments,
argIndex = 0,
argLength = args.length;
for ( ; argIndex for ( var i = 0; i { <.length if args argindex list i>// 處理firingIndex 和firingLength
if (firing ) {
if ( i firingLength--;
if ( i fireingIndex--;
}
}
}
//刪除元素
list.splice( i--, 1 ) ;
// 如果我們有一些唯一性屬性,那麼
// 我們只需要執行一次
if ( flags.unique ) {
break;
}
}
}
}
}
回傳此;
},
// 控制給定回呼是否在列表中
has: function( fn ) {
if (list ) {
var i = 0,
length =列表長度;
for ( ; i if ( fn === list[ i ] ) {
返回true;
}
}
}
回傳false;
},
// 從清單中移除所有回呼
empty: function() {
list = [];
回傳這個;
},
// 讓清單不再執行任何動作
disable: function() {
list = stack = memory = undefined;
回傳這個;
},
//是否禁用?
停用:function() {
return !list;
},
// 將清單鎖定在目前狀態
lock: function() {
stack = undefined;
if ( !內存|| 內存=== true ) {
self.disable();
}
返回此;
},
//是否已鎖定?
鎖定: function() {
return !stack;
},
// 使用給定的上下文和參數呼叫所有回呼
fireWith: function( context, args ) {
if ( stack ) {
if (fireing ) {
if ( !flags.once ) {
stack.push( [ context, args ] );
}
} else if ( !( flags.once && memory ) ) {
fire( context, args );
}
}
傳回此;
},
// 使用給定參數呼叫所有回呼
fire: function() {
self.fireWith( this,arguments );
回傳這個;
},
// 了解回呼是否已被呼叫至少一次
fired : function() {
return !!memory;
}
};
回自我;
};
})( jQuery );
})( jQuery );
複製程式碼
如下程式碼:
(function( jQuery ) {
{},
sliceTopic = [].slice;
jQuery.Topic = function( id ) {
var 回呼,
方法,
topic = id && 主題[ id ]; topic ) {
callbacks = jQuery.Callbacks()
topic = {
發布:callbacks.fire,
訂閱:callbacks.add,
取消訂閱:callbacks.remove
} ; 🎜>if ( id ) {
topics[ id ] = topic;
}
返回主題
}
jQuery.extend({
訂閱: function( id ) {
var topic = jQuery.Topic( id ),
args = sliceTopic.call(args, 1 );
topic.subscribe.apply( topic, args ); return {
主題:主題,
主題:主題,args
};
取消訂閱:函數( id ) {
var topic = id && id.topic || jQuery.主題( id );
topic.unsubscribe.apply( topic, id && id.args ||
sliceTopic.call( 參數, 1 ) );
},
發佈: 函數( id ) {
var topic = jQuery.Topic( id );
topic.publish.apply( topic, sliceTopic.call(arguments, 1 ) );
}
});
})( jQuery );
雖然把大量程式碼移動回調,但1.7的Deferred卻一點沒變小,它變得更重型,由三個函數列隊組成了。而回傳的是Promise對象,比原來多長了pipe, state,progress,always方法。 ajax端變成這樣:
deferredred = jQuery.Deferred (),
completeDeferred = jQuery.Callbacks( "一次記憶體" ),
deferred.promise( jqXHR );
jqXHR.success = jqXHR.done;
jqqHR.eror =
jqXHR.complete =completeDeferred.add;
隊列兩邊也變了多少。
複製程式碼程式碼如下: (function( jQuery ) {
function handleQueueMarkDefer( elem, type, src ) {
var deferDataKey = type "defer",
queue🎜>var deferDataKey = type "defer",
queue🎜>var deferDataKey = type "defer",
= type "mark",
defer = jQuery._data( elem, deferDataKey );
if ( defer &&
( src === "queue" || !jQuery._data(Keyelem, queueData) ) ; &&
( src === "mark" || !jQuery._data(elem, markDataKey) ) ) {
// 為硬編碼回調提供空間,首先觸發
// 最後標記/在元素上排隊其他內容
setTimeout( function() {
if ( !jQuery._data( elem,queueDataKey ) &&
!jQuery._data( elem, markDataKey ) ) {
!jQuery._data( elem, markDataKey ) ) {
jQuery.removeKey ) ) {
jQuery.removeKey ) ) {
jQuery.removeKey ) ) {
jQuery.removeKey ( elem, deferDataKey, true );
defer.fire()
}
}, 0 );
}
}
jQuery.extend({
_mark: function( elem, type ) {
if ( elem ) {
type = ( type || "fx" ) "mark";
jQuery._data( elem, type, (jQuery._data( elem,型) || 0) 1 );
}
},
_unmark: function(force, elem, type ) {
if (force !== true ) {
type = elem ;
元素=力
力=假;
}
if ( elem ) {
type = type || “fx”;
var key = 輸入“mark”,
count = 力? else {
jQuery.removeData( elem, key, true );
handleQueueMarkDefer( elem, type, "mark" );
}
}
},
: function( elem, type, data ) {
var q;
if ( elem ) {
type = ( type || "fx" ) "queue";
q = jQuery._data( elem, 類型);
// 如果這只是一個查找,則透過快速退出來加速出隊
if ( data ) {
if ( !q || jQuery.isArray(data) ) {
q = jQuery. _data( elem, 類型, jQuery.makeArray(data) );
} else {
q.push( 資料);
}
}
回傳q || [] ;
}
},
出隊: function( elem, type ) {
type = type || “fx”;
var queue = jQuery.queue( elem, type ),
fn = queue.shift(),
hooks = {};
// 如果fx 隊伍列出隊,總是刪除進度標記
if ( fn === "inprogress" ) {
fn = queue.shift();
}
if ( fn ) {
// 增加進度哨兵,防止fx 佇列被
// 自動出列
if ( type === "fx" ) {
queue.unshift(“進行中”);
}
jQuery._data( elem, type ".run", hooks );
fn.call( elem, function() {
jQuery.dequeue( elem, type );
}, hooks );
}
if ( !queue.length ) {
jQuery.removeData(elemqueue.length ) {
jQuery.removeData(elemem, type "queue " type ".run", true );
handleQueueMarkDefer( elem, type, "queue" );
}
}
});
jQuery.fn.extend( {
queue: function( type, data ) {
var setter = 2;
if ( typeof type !== "string" ) {
data = type;
type = "fx ";
setter --
}
if (args.length
return jQuery.queue( this[0], type ) ;
}
回傳資料= == 未定義
this :
this.each(function() {
var queue = jQuery.queue( this, type, data );
if ( type === "fx" && queue[0] !== "inprogress" ) {
jQuery.dequeue( this, type );
}
});
出隊: function( type ) {
return this .each(function() {
jQuery.dequeue( this, type );
});
},
//基於Clint Helfers 的插件,經許可
// http: //blindsignals.com/index.php/2009/07/jquery-delay/
delay: function( time, type ) {
time = jQuery.fx ? jQuery.fx.speeds[ time ] || time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
type = type || "fx"; {
var timeout = setTimeout( next, time );
hooks.stop = function() {
clearTimeout( timeout )
}); 🎜>clearQueue: function( type ) {
return this.queue( type || “fx”,[]);
},
// 當某種類型的隊列被清空時,得到一個已解決的Promise
// (fx 是預設型別)
promise: function( type, object ) {
if ( typeof type !== "string" ) {
object = type;
類型=未定義;
}
類型= 類型|| “fx”;
var defer = jQuery.Deferred(),
elements = this,
i = elements.length,
count = 1,
deferDataKey = type "defer",
queueDataKey =輸入“佇列”,
markDataKey = 輸入“標記”,
tmp
;函數resolve() {
if ( !( --count ) ) {
defer.resolveWith( elements, [ elements ] );
}
}
while( i-- ) {
if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) ||
( jQuery.data ( elements[ i ],queueDataKey, undefined, true ) ||
>jery .data( elements[ i ], markDataKey, undefined, true ) ) &&
jQuery.data( elements[ i ], deferDataKey, jQuery. Callbacks( "一次記憶" ), true ) )) {
count ;
tmp.add( 解析);
}
}
resolve();
回傳defer.promise( 物件);
}
});
} )( jQuery );
這時候,鉤子機制其實已經在jQuery內部蔓延起來,1.5是css模組的cssHooks,1.6是屬性模組的attrHooks, propHooks, boolHooks, nodeHooks,1.7是事件模組的fixHooks, keyHooks, mouseHooks,1.模組的_queueHooks,由於_queueHooks,queue終於瘦身了。
View Code?/1.8
View Code?/1.8
jery.ext ({
queue: function( elem, type, data ) {
var queue;
if ( elem ) {
type = ( type || "fx" ) "queue";
queue = jQuery._data( elem, type );
// Speed up dequeue by getting out quickly if this is just a lookup
if ( data ) {
if ( !queue ||Query.isray(3( data) ) {
queue = jQuery._data( elem, type, jQuery.makeArray(data) );
} else {
queue.push( data );
}
}
}
return queue || [];
}
},
dequeue: function( elem, type ) {
type = type || "fx";
var queue = jQuery. queue( elem, type ),
fn = queue.shift(),
hooks = jQuery._queueHooks( elem, type ),
next = function() {
jQuery.dequeue( elem, type );
};
// If the fx queue is dequeued, always remove the progress sentinel
if ( fn === "inprogress" ) {
fn = queue.shift();
}
if ( fn ) {
// Add a progress sentinel to prevent the fx queue from being
// automatically dequeued
if ( type === "fx" ) {
queue.unshift( "inprogress" );
}
// clear up the last queue stop function
delete hooks.stop;
fn.call( elem, next
}
if ( !queue.length && hooks ) {
hooks.empty.fire();
}
},
// not intended for public consumption - generates a queueH object, 或 returns the current one
_queueHooks: function( elem, type ) {
var key = type "queueHooks";
return jQuery._data( elem, key key) || Query. key, {
empty: jQuery.Callbacks("once memory").add(function() {
jQuery.removeData( elem, type "queue", true );
jQuery.removeData( elem, key, true );
})
});
}
});
jQuery.fn.extend({
queue: function( type, data ) {
var setter = 2;
if ( typeof type !== "string" ) {
data = type;
type = "fx";
s--;
}
}
if ( arguments.length return jQuery.queue( this[0], type );
}
return data === undefined ?
this :
return data === undefined ?
this :
this. each(function() {
var queue = jQuery.queue( this, type, data );
// ensure a hooks for this queue
jQuery._queueHooks( this, type );
jQuery._queueHooks( this, type );
if
if ( type === "fx" && queue[0] !== "inprogress" ) {
jQuery.dequeue( this, type );
}
});
},
dequeue: function( type ) {
return this.each(function() {
jQuery.dequeue( this, type );
});
},
// Based off of the plugin by Clint Helfers, with permission.
// http://blindsignals.com/index.php/2009/07/jquery-delay/
delay: function( time, type ) {
time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
type = type || "fx";
return this.queue( type, function( next, hooks ) {
var timeout = setTimeout( next, time );
hooks.stop = function() {
clearTimeout( timeout );
};
});
}
}; clearQueue: function( type ) {
return this.queue( type || "fx", [] );
},
// Get a promise resolved when queues of a certain type
/ / are emptied (fx is the type by default)
promise: function( type, obj ) {
var tmp,
count = 1,
defer = jQuery.Deferred(>count = 1,
defer = jQuery.Deferred(), 🎜> elements = this,
i = this.length,
resolve = function() {
if ( !( --count ) ) {
defer.resolveWith( elements, [ elements ] );
}
};
if ( typeof type !== "string" ) {
obj = type;
type = undefined;
}
type = type || " fx";
while( i-- ) {
if ( (tmp = jQuery._data( elements[ i ], type "queueHooks" )) && tmp.empty ) {
count ;
tmp.empty.add( resolve );
} 同時,動畫模組迎來了它第三次大重構,它也有一個鉤子Tween.propHooks。它多出兩個對象,其中Animation返回一個非同步列隊,Tween 是用於處理單一樣式或屬性的變化,相當於之前Fx對象。 animate被抽空了,它在1.72可是近百行的規模。 jQuery透過鉤子機制與分化出一些新的對象,將一些巨型方法重建。現在非常長的方法只龜縮在節點模組,回呼模組。 複製程式碼 程式碼如下:
animate: function( prop, speed, easing, callback ) {
var empty = jQuery.isEmptyObject( prop ),
optall = jQuery.speed( speed, easing, callback ), doAnimation = function() {
// Operate on a copy of prop so per-property easing won't be lost
var anim = Animation( this, jQuery.extend( {}, prop ), optall ) ;
// Empty animations resolve immediately
if ( empty ) {
anim.stop( );
}
};
return empty || optall.queue = ||== false ?
this.each( doAnimation ) :
this.queue( optall.queue, doAnimation );
},
到目前為止,所有異步的東西都被jQuery改造成非同步列隊的「子類」或叫「變種」比較合適些。如domReady, 動畫,AJAX,與執行了promise或delay或各種特效方法之後的jQuery物件。於是所有非同步的東西在promise的加護下,像同步那樣寫非同步程式。