您好,欢迎访问一九零五行业门户网

jquery1.83 之前所有与异步列队相关的模块详细介绍_jquery

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机制。下面是一个比较列表:
dojo jquery 注解
addboth then 同时添加正常回调与错误回调
addcallback done 添加正常回调
adderrback fail 添加错误回调
callback done 执行所有正常回调
errback reject 执行所有错误回调
donewith 在指定作用域下执行所有正常回调,但dojo已经在addcallback上指定好了
rejectwith 在指定作用域下执行所有错误回调,但dojo已经在adderrback上指定好了
promise 返回一个外界不能改变其状态的deferred对象(外称为promise对象)
jquery的when方法用于实现回调的回调,或者说,几个异列列队都执行后才执行另外的一些回调。这些后来的回调也是用done, when, fail添加的,但when返回的这个对象已经添加让用户控制它执行的能力了。因为这时它是种叫promise的东西,只负责添加回调与让用户窥探其状态。一旦前一段回调都触发了,它就自然进入正常回调列队(deferred ,见deferred方法的定义)或错误回调列队(faildeferred )中去。不过我这样讲,对于没有异步编程经验的人来说,肯定听得云里雾里。看实例好了。
复制代码 代码如下:
$.when({aa:1}, {aa:2}).done(function(a,b){
console.log(a.aa)
console.log(b.aa)
});
直接输出1,2。如果是传入两个函数,也是返回两个函数。因此对于普通的数据类型,前面的when有多少个参数,后面的done, fail方法的回调就有多少个参数。
复制代码 代码如下:
function fn(){
return 4;
}
function log(s){
window.console && console.log(s)
}
$.when( { num:1 }, 2, '3', fn() ).done(function(o1, o2, o3, o4){
log(o1.num);
log(o2);
log(o3);
log(o4);
});
如果我们想得到各个异步的结果,我们需要用resolve, resolvewith, reject, rejectwith进行传递它们。
复制代码 代码如下:
var log = function(msg){
window.console && console.log(msg)
}
function asyncthing1(){
var dfd = $.deferred();
settimeout(function(){
log('asyncthing1 seems to be done...');
dfd.resolve('1111');
},1000);
return dfd.promise();
}
function asyncthing2(){
var dfd = $.deferred();
settimeout(function(){
log('asyncthing2 seems to be done...');
dfd.resolve('222');
},1500);
return dfd.promise();
}
function asyncthing3(){
var dfd = $.deferred();
settimeout(function(){
log('asyncthing3 seems to be done...');
dfd.resolve('333');
},2000);
return dfd.promise();
}
/* do it */
$.when( asyncthing1(), asyncthing2(), asyncthing3() ).done(function(res1, res2, res3){
log('all done!');
log(res1 + ', ' + res2 + ', ' + res3);
})
异步列队一开始没什么人用(现在也没有什么人用,概念太抽象了,方法名起得太烂了),于是它只能在内部自产自销。首先被染指的是queue。queue模块是1.4为吸引社区的delay插件,特地从data模块中分化的产物,而data则是从event模块化分出来的。jquery新模块的诞生总是因为用户对已有api的局限制不满而致。最早的queue模块的源码:
复制代码 代码如下:
jquery.extend({
queue: function( elem, type, data ) {
if ( !elem ) {
return;
}
type = (type || fx) + queue;
var q = jquery.data( elem, type );
// speed up dequeue by getting out quickly if this is just a lookup
if ( !data ) {
return q || [];
}
if ( !q || jquery.isarray(data) ) {
q = jquery.data( elem, type, jquery.makearray(data) );
} else {
q.push( data );
}
return q;
},
dequeue: function( elem, type ) {
type = type || fx;
var queue = jquery.queue( elem, type ), fn = queue.shift();
// 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);
}
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, 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() {
var elem = this;
settimeout(function() {
jquery.dequeue( elem, type );
}, time );
});
},
clearqueue: function( type ) {
return this.queue( type || fx, [] );
}
});
1.6添加了_mark,_unmark,promise。queue是让函数同属一个队伍里面,目的是让动画一个接一个执行。_mark则是让它们各自拥有队伍,并列执行(虽然它们只记录异步列队中已被执行的函数个数)。promise则在这些并发执行的动画执行后才执行另些一些回调(或动画)。
复制代码 代码如下:
(function( jquery ) {
function handlequeuemarkdefer( elem, type, src ) {
//清空记录deferred个数的字段,函数列队与异步列队
var deferdatakey = 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 ) ) ) {
// give room for hard-coded callbacks to fire first
// and eventually mark/queue something else on the element
settimeout( function() {
if ( !jquery.data( elem, queuedatakey, undefined, true ) &&
!jquery.data( elem, markdatakey, undefined, true ) ) {
jquery.removedata( elem, deferdatakey, true );
defer.resolve();
}
}, 0 );
}
}
jquery.extend({
_mark: function( elem, type ) {
if ( elem ) {
type = (type || fx) + mark;//创建一个以mark为后缀的字段,用于记录此列队中个数
jquery.data( elem, type, (jquery.data(elem,type,undefined,true) || 0) + 1, true );
}
},
_unmark: function( force, elem, type ) {
if ( force !== true ) {
type = elem;
elem = force;
force = false;
}
if ( elem ) {
type = type || fx;
var key = type + mark,
//让个数减1,如果第一个参数为true,就强逼减至0
count = force ? 0 : ( (jquery.data( elem, key, undefined, true) || 1 ) - 1 );
if ( count ) {
jquery.data( elem, key, count, true );
} else {//如果为0,就移除它
jquery.removedata( elem, key, true );
handlequeuemarkdefer( elem, type, mark );
}
}
},
queue: function( elem, type, data ) {
if ( elem ) {
type = (type || fx) + queue;
var q = jquery.data( elem, type, undefined, true );
// speed up dequeue by getting out quickly if this is just a lookup
if ( data ) {
if ( !q || jquery.isarray(data) ) {
q = jquery.data( elem, type, jquery.makearray(data), true );
} else {
q.push( data );
}
}
return q || [];
}
},
dequeue: function( elem, type ) {
type = type || fx;
var queue = jquery.queue( elem, type ),
fn = queue.shift(),
defer;
// 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);
}
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( 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() {
var elem = this;
settimeout(function() {
jquery.dequeue( elem, type );
}, time );
});
},
clearqueue: function( type ) {
return this.queue( type || fx, [] );
},
//把jquery对象装进一个异步列队,允许它在一系列动画中再执行之后绑定的回调
promise: function( type, object ) {
if ( typeof type !== string ) {
object = type;
type = undefined;
}
type = type || fx;
var defer = jquery.deferred(),
elements = this,
i = elements.length,
count = 1,
deferdatakey = type + defer,
queuedatakey = type + queue,
markdatakey = type + mark;
function resolve() {
if ( !( --count ) ) {
defer.resolvewith( elements, [ elements ] );
}
}
while( i-- ) {
//如果它之前已经使用过unmark, queue等方法,那么我们将生成一个新的deferred放进缓存系统
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 ], deferdatakey, jquery._deferred(), true ) )) {
count++;
tmp.done( resolve );
}
}
resolve();
return defer.promise();
}
});
})( jquery );
jquery.ajax模块也被染指,$.xhr对象,当作httpxmlrequest对象的仿造器是由一个deferred对象与一个_deferred的对象构成。
复制代码 代码如下:
deferred = jquery.deferred(),
completedeferred = 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 ) {
// string to object flags format cache
var flagscache = {};
// convert string-formatted flags into object-formatted ones and store in cache
function createflags( flags ) {
var object = flagscache[ flags ] = {},
i, length;
flags = flags.split( /\s+/ );
for ( i = 0, length = flags.length; i object[ flags[i] ] = true;
}
return object;
}
/*
* create a callback list using the following parameters:
*
* flags: an optional list of space-separated flags that will change how
* the callback list behaves
*
* by default a callback list will act like an event callback list and can be
* fired multiple times.
*
* possible flags:
*
* once: will ensure the callback list can only be fired once (like a deferred)
*
* memory: will keep track of previous values and will call any callback added
* after the list has been fired right away with the latest memorized
* values (like a deferred)
*
* unique: will ensure a callback can only be added once (no duplicate in the list)
*
* stoponfalse: interrupt callings when a callback returns false
*
*/
jquery.callbacks = function( flags ) {
// convert flags from string-formatted to object-formatted
// (we check in cache first)
flags = flags ? ( flagscache[ flags ] || createflags( flags ) ) : {};
var // actual callback list
list = [],
// stack of fire calls for repeatable lists
stack = [],
// last fire value (for non-forgettable lists)
memory,
// flag to know if list is currently firing
firing,
// first callback to fire (used internally by add and firewith)
firingstart,
// end of the loop when firing
firinglength,
// index of currently firing callback (modified by remove if needed)
firingindex,
// add one or several callbacks to the list
add = function( args ) {
var i,
length,
elem,
type,
actual;
for ( i = 0, length = args.length; i elem = args[ i ];
type = jquery.type( elem );
if ( type === array ) {
// inspect recursively
add( elem );
} else if ( type === function ) {
// add if not in unique mode and callback is not in
if ( !flags.unique || !self.has( elem ) ) {
list.push( elem );
}
}
}
},
// fire callbacks
fire = function( context, args ) {
args = args || [];
memory = !flags.memory || [ context, args ];
firing = true;
firingindex = firingstart || 0;
firingstart = 0;
firinglength = list.length;
for ( ; list && firingindex if ( list[ firingindex ].apply( context, args ) === false && flags.stoponfalse ) {
memory = true; // mark as halted
break;
}
}
firing = false;
if ( list ) {
if ( !flags.once ) {
if ( stack && stack.length ) {
memory = stack.shift();
self.firewith( memory[ 0 ], memory[ 1 ] );
}
} else if ( memory === true ) {
self.disable();
} else {
list = [];
}
}
},
// actual callbacks object
self = {
// add a callback or a collection of callbacks to the list
add: function() {
if ( list ) {
var length = list.length;
add( arguments );
// do we need to add the callbacks to the
// current firing batch?
if ( firing ) {
firinglength = list.length;
// with memory, if we're not firing then
// we should call right away, unless previous
// firing was halted (stoponfalse)
} else if ( memory && memory !== true ) {
firingstart = length;
fire( memory[ 0 ], memory[ 1 ] );
}
}
return this;
},
// remove a callback from the list
remove: function() {
if ( list ) {
var args = arguments,
argindex = 0,
arglength = args.length;
for ( ; argindex for ( var i = 0; i if ( args[ argindex ] === list[ i ] ) {
// handle firingindex and firinglength
if ( firing ) {
if ( i firinglength--;
if ( i firingindex--;
}
}
}
// remove the element
list.splice( i--, 1 );
// if we have some unicity property then
// we only need to do this once
if ( flags.unique ) {
break;
}
}
}
}
}
return this;
},
// control if a given callback is in the list
has: function( fn ) {
if ( list ) {
var i = 0,
length = list.length;
for ( ; i if ( fn === list[ i ] ) {
return true;
}
}
}
return false;
},
// remove all callbacks from the list
empty: function() {
list = [];
return this;
},
// have the list do nothing anymore
disable: function() {
list = stack = memory = undefined;
return this;
},
// is it disabled?
disabled: function() {
return !list;
},
// lock the list in its current state
lock: function() {
stack = undefined;
if ( !memory || memory === true ) {
self.disable();
}
return this;
},
// is it locked?
locked: function() {
return !stack;
},
// call all callbacks with the given context and arguments
firewith: function( context, args ) {
if ( stack ) {
if ( firing ) {
if ( !flags.once ) {
stack.push( [ context, args ] );
}
} else if ( !( flags.once && memory ) ) {
fire( context, args );
}
}
return this;
},
// call all the callbacks with the given arguments
fire: function() {
self.firewith( this, arguments );
return this;
},
// to know if the callbacks have already been called at least once
fired: function() {
return !!memory;
}
};
return self;
};
})( jquery );
这期间有还个小插曲,jquery团队还想增加一个叫topic的模块,内置发布者订阅者机制,但这封装太溥了,结果被否决。
复制代码 代码如下:
(function( jquery ) {
var topics = {},
slicetopic = [].slice;
jquery.topic = function( id ) {
var callbacks,
method,
topic = id && topics[ id ];
if ( !topic ) {
callbacks = jquery.callbacks();
topic = {
publish: callbacks.fire,
subscribe: callbacks.add,
unsubscribe: callbacks.remove
};
if ( id ) {
topics[ id ] = topic;
}
}
return topic;
};
jquery.extend({
subscribe: function( id ) {
var topic = jquery.topic( id ),
args = slicetopic.call( arguments, 1 );
topic.subscribe.apply( topic, args );
return {
topic: topic,
args: args
};
},
unsubscribe: function( id ) {
var topic = id && id.topic || jquery.topic( id );
topic.unsubscribe.apply( topic, id && id.args ||
slicetopic.call( arguments, 1 ) );
},
publish: function( id ) {
var topic = jquery.topic( id );
topic.publish.apply( topic, slicetopic.call( arguments, 1 ) );
}
});
})( jquery );
虽然把大量代码移动callbacks,但1.7的deferred却一点没有没变小,它变得更重型,它由三个函数列队组成了。并且返回的是promise对象,比原来多出了pipe, state, progress, always方法。ajax那边就变成这样:
复制代码 代码如下:
deferred = jquery.deferred(),
completedeferred = jquery.callbacks( once memory ),
deferred.promise( jqxhr );
jqxhr.success = jqxhr.done;
jqxhr.error = jqxhr.fail;
jqxhr.complete = completedeferred.add;
queue那边也没变多少。
复制代码 代码如下:
(function( jquery ) {
function handlequeuemarkdefer( elem, type, src ) {
var deferdatakey = type + defer,
queuedatakey = type + queue,
markdatakey = type + mark,
defer = jquery._data( elem, deferdatakey );
if ( defer &&
( src === queue || !jquery._data(elem, queuedatakey) ) &&
( src === mark || !jquery._data(elem, markdatakey) ) ) {
// give room for hard-coded callbacks to fire first
// and eventually mark/queue something else on the element
settimeout( function() {
if ( !jquery._data( elem, queuedatakey ) &&
!jquery._data( elem, markdatakey ) ) {
jquery.removedata( 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, type ) || 0) + 1 );
}
},
_unmark: function( force, elem, type ) {
if ( force !== true ) {
type = elem;
elem = force;
force = false;
}
if ( elem ) {
type = type || fx;
var key = type + mark,
count = force ? 0 : ( (jquery._data( elem, key ) || 1) - 1 );
if ( count ) {
jquery._data( elem, key, count );
} else {
jquery.removedata( elem, key, true );
handlequeuemarkdefer( elem, type, mark );
}
}
},
queue: function( elem, type, data ) {
var q;
if ( elem ) {
type = ( type || fx ) + queue;
q = jquery._data( elem, type );
// speed up dequeue by getting out quickly if this is just a lookup
if ( data ) {
if ( !q || jquery.isarray(data) ) {
q = jquery._data( elem, type, jquery.makearray(data) );
} else {
q.push( data );
}
}
return q || [];
}
},
dequeue: function( elem, type ) {
type = type || fx;
var queue = jquery.queue( elem, type ),
fn = queue.shift(),
hooks = {};
// 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 );
}
jquery._data( elem, type + .run, hooks );
fn.call( elem, function() {
jquery.dequeue( elem, type );
}, hooks );
}
if ( !queue.length ) {
jquery.removedata( elem, 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 ( arguments.length return jquery.queue( this[0], type );
}
return data === undefined ?
this :
this.each(function() {
var queue = jquery.queue( this, type, data );
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, object ) {
if ( typeof type !== string ) {
object = type;
type = undefined;
}
type = type || fx;
var defer = jquery.deferred(),
elements = this,
i = elements.length,
count = 1,
deferdatakey = type + defer,
queuedatakey = type + queue,
markdatakey = type + mark,
tmp;
function 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 ) ||
jquery.data( elements[ i ], markdatakey, undefined, true ) ) &&
jquery.data( elements[ i ], deferdatakey, jquery.callbacks( once memory ), true ) )) {
count++;
tmp.add( resolve );
}
}
resolve();
return defer.promise( object );
}
});
})( jquery );
这时候,钩子机制其实已经在jquery内部蔓延起来,1.5是css模块的csshooks,1.6是属性模块的attrhooks, prophooks, boolhooks, nodehooks,1.7是事件模块的fixhooks, keyhooks, mousehooks,1.8是queue模块的_queuehooks,由于_queuehooks,queue终于瘦身了。
复制代码 代码如下:
view code?//1.8
jquery.extend({
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 || jquery.isarray(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, hooks );
}
if ( !queue.length && hooks ) {
hooks.empty.fire();
}
},
// not intended for public consumption - generates a queuehooks object, or returns the current one
_queuehooks: function( elem, type ) {
var key = type + queuehooks;
return jquery._data( elem, key ) || jquery._data( elem, 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;
setter--;
}
if ( arguments.length return jquery.queue( this[0], type );
}
return data === undefined ?
this :
this.each(function() {
var queue = jquery.queue( this, type, data );
// ensure a hooks for this queue
jquery._queuehooks( this, type );
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(),
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 );
}
}
resolve();
return defer.promise( obj );
}
});
同时,动画模块迎来了它第三次大重构,它也有一个钩子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( true );
}
};
return empty || optall.queue === false ?
this.each( doanimation ) :
this.queue( optall.queue, doanimation );
},
到目前为止,所有异步的东西都被jquery改造成异步列队的“子类”或叫“变种”更合适些。如domready, 动画,ajax,与执行了promise或delay或各种特效方法之后的jquery对象。于是所有异步的东西在promise的加护下,像同步那样编写异步程序。
其它类似信息

推荐信息