首页 > web前端 > js教程 > jquery1.83 之前所有与异步列队相关的模块详细介绍_jquery

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

WBOY
发布: 2016-05-16 17:48:18
原创
1185 人浏览过

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 ); // 如果只是查找,则可以快速出队
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, 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 ) {
//清空记录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 ) ) ) {
// 为硬编码回调提供空间,以便首先触发
// 并最终在元素上标记/排队其他内容
setTimeout( function() {
if ( !jQuery.data( elem,queueDataKey, undefined, true ) &&
!jQuery.data( elem, markDataKey, undefined, true ) ) {
jQuery.removeData( elem, deferDataKey, true ); .resolve();
}
}, 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 ], deferDataKey, jQuery._Deferred(), true ) )) {
count ;
tmp.done( 解决 );
}
}
resolve();
返回 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 ) {
// 字符串到对象标志格式缓存
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 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 ) === false && flags.stopOnFalse ) {
内存 = true; // 标记为停止
break;
}
}
开火= false;
if ( list ) {
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]);
}
}
返回此;
},
// 从列表中删除回调
remove: function() {
if ( list ) {
var args = arguments,
argIndex = 0,
argLength = args.length;
for ( ; argIndex for ( var i = 0; i 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 ) {
var topic = {},
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端就变成这样:



复制代码
代码如下: deferred = jQuery.Deferred(), completeDeferred = jQuery.Callbacks( "一次内存" ),
deferred.promise( jqXHR );
jqXHR.success = jqXHR.done;
jqXHR.error = jqXHR.fail;
jqXHR.complete =completeDeferred.add;


队列两边也变了多少。



复制代码
代码如下:

(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) ) ) {
// 为硬编码回调提供空间,首先触发
// 最后标记/在元素上排队其他内容
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,类型 ) || 0) 1 );
}
},
_unmark: function(force, elem, type ) {
if (force !== true ) {
type = elem ;
元素=力
力=假;
}
if ( elem ) {
type = type || “fx”;
var key = 输入“mark”,
count = 力? 0 : ( (jQuery._data( elem, key ) || 1) - 1 );
if ( count ) {
jQuery._data( elem, key, 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( 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 (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 : 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 ) ||
jQuery.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.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 < setter ) {
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的加护下,像同步那样编写异步程序。
相关标签:
来源:php.cn
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板