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

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

May 16, 2016 pm 05:48 PM

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的加护下,像同步那样编写异步程序。
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.聊天命令以及如何使用它们
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

如何创建和发布自己的JavaScript库? 如何创建和发布自己的JavaScript库? Mar 18, 2025 pm 03:12 PM

文章讨论了创建,发布和维护JavaScript库,专注于计划,开发,测试,文档和促销策略。

如何在浏览器中优化JavaScript代码以进行性能? 如何在浏览器中优化JavaScript代码以进行性能? Mar 18, 2025 pm 03:14 PM

本文讨论了在浏览器中优化JavaScript性能的策略,重点是减少执行时间并最大程度地减少对页面负载速度的影响。

前端热敏纸小票打印遇到乱码问题怎么办? 前端热敏纸小票打印遇到乱码问题怎么办? Apr 04, 2025 pm 02:42 PM

前端热敏纸小票打印的常见问题与解决方案在前端开发中,小票打印是一个常见的需求。然而,很多开发者在实...

如何使用浏览器开发人员工具有效调试JavaScript代码? 如何使用浏览器开发人员工具有效调试JavaScript代码? Mar 18, 2025 pm 03:16 PM

本文讨论了使用浏览器开发人员工具的有效JavaScript调试,专注于设置断点,使用控制台和分析性能。

谁得到更多的Python或JavaScript? 谁得到更多的Python或JavaScript? Apr 04, 2025 am 12:09 AM

Python和JavaScript开发者的薪资没有绝对的高低,具体取决于技能和行业需求。1.Python在数据科学和机器学习领域可能薪资更高。2.JavaScript在前端和全栈开发中需求大,薪资也可观。3.影响因素包括经验、地理位置、公司规模和特定技能。

如何使用源地图调试缩小JavaScript代码? 如何使用源地图调试缩小JavaScript代码? Mar 18, 2025 pm 03:17 PM

本文说明了如何使用源地图通过将其映射回原始代码来调试JAVASCRIPT。它讨论了启用源地图,设置断点以及使用Chrome DevTools和WebPack之类的工具。

console.log输出结果差异:两次调用为何不同? console.log输出结果差异:两次调用为何不同? Apr 04, 2025 pm 05:12 PM

深入探讨console.log输出差异的根源本文将分析一段代码中console.log函数输出结果的差异,并解释其背后的原因。�...

初学者的打字稿,第2部分:基本数据类型 初学者的打字稿,第2部分:基本数据类型 Mar 19, 2025 am 09:10 AM

掌握了入门级TypeScript教程后,您应该能够在支持TypeScript的IDE中编写自己的代码,并将其编译成JavaScript。本教程将深入探讨TypeScript中各种数据类型。 JavaScript拥有七种数据类型:Null、Undefined、Boolean、Number、String、Symbol(ES6引入)和Object。TypeScript在此基础上定义了更多类型,本教程将详细介绍所有这些类型。 Null数据类型 与JavaScript一样,TypeScript中的null

See all articles