搜索
首页web前端js教程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 ); // 如果只是查找,则可以快速出队
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 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
JavaScript和Web:核心功能和用例JavaScript和Web:核心功能和用例Apr 18, 2025 am 12:19 AM

JavaScript在Web开发中的主要用途包括客户端交互、表单验证和异步通信。1)通过DOM操作实现动态内容更新和用户交互;2)在用户提交数据前进行客户端验证,提高用户体验;3)通过AJAX技术实现与服务器的无刷新通信。

了解JavaScript引擎:实施详细信息了解JavaScript引擎:实施详细信息Apr 17, 2025 am 12:05 AM

理解JavaScript引擎内部工作原理对开发者重要,因为它能帮助编写更高效的代码并理解性能瓶颈和优化策略。1)引擎的工作流程包括解析、编译和执行三个阶段;2)执行过程中,引擎会进行动态优化,如内联缓存和隐藏类;3)最佳实践包括避免全局变量、优化循环、使用const和let,以及避免过度使用闭包。

Python vs. JavaScript:学习曲线和易用性Python vs. JavaScript:学习曲线和易用性Apr 16, 2025 am 12:12 AM

Python更适合初学者,学习曲线平缓,语法简洁;JavaScript适合前端开发,学习曲线较陡,语法灵活。1.Python语法直观,适用于数据科学和后端开发。2.JavaScript灵活,广泛用于前端和服务器端编程。

Python vs. JavaScript:社区,图书馆和资源Python vs. JavaScript:社区,图书馆和资源Apr 15, 2025 am 12:16 AM

Python和JavaScript在社区、库和资源方面的对比各有优劣。1)Python社区友好,适合初学者,但前端开发资源不如JavaScript丰富。2)Python在数据科学和机器学习库方面强大,JavaScript则在前端开发库和框架上更胜一筹。3)两者的学习资源都丰富,但Python适合从官方文档开始,JavaScript则以MDNWebDocs为佳。选择应基于项目需求和个人兴趣。

从C/C到JavaScript:所有工作方式从C/C到JavaScript:所有工作方式Apr 14, 2025 am 12:05 AM

从C/C 转向JavaScript需要适应动态类型、垃圾回收和异步编程等特点。1)C/C 是静态类型语言,需手动管理内存,而JavaScript是动态类型,垃圾回收自动处理。2)C/C 需编译成机器码,JavaScript则为解释型语言。3)JavaScript引入闭包、原型链和Promise等概念,增强了灵活性和异步编程能力。

JavaScript引擎:比较实施JavaScript引擎:比较实施Apr 13, 2025 am 12:05 AM

不同JavaScript引擎在解析和执行JavaScript代码时,效果会有所不同,因为每个引擎的实现原理和优化策略各有差异。1.词法分析:将源码转换为词法单元。2.语法分析:生成抽象语法树。3.优化和编译:通过JIT编译器生成机器码。4.执行:运行机器码。V8引擎通过即时编译和隐藏类优化,SpiderMonkey使用类型推断系统,导致在相同代码上的性能表现不同。

超越浏览器:现实世界中的JavaScript超越浏览器:现实世界中的JavaScriptApr 12, 2025 am 12:06 AM

JavaScript在现实世界中的应用包括服务器端编程、移动应用开发和物联网控制:1.通过Node.js实现服务器端编程,适用于高并发请求处理。2.通过ReactNative进行移动应用开发,支持跨平台部署。3.通过Johnny-Five库用于物联网设备控制,适用于硬件交互。

使用Next.js(后端集成)构建多租户SaaS应用程序使用Next.js(后端集成)构建多租户SaaS应用程序Apr 11, 2025 am 08:23 AM

我使用您的日常技术工具构建了功能性的多租户SaaS应用程序(一个Edtech应用程序),您可以做同样的事情。 首先,什么是多租户SaaS应用程序? 多租户SaaS应用程序可让您从唱歌中为多个客户提供服务

See all articles

热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.能量晶体解释及其做什么(黄色晶体)
1 个月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
1 个月前By尊渡假赌尊渡假赌尊渡假赌
威尔R.E.P.O.有交叉游戏吗?
1 个月前By尊渡假赌尊渡假赌尊渡假赌

热工具

安全考试浏览器

安全考试浏览器

Safe Exam Browser是一个安全的浏览器环境,用于安全地进行在线考试。该软件将任何计算机变成一个安全的工作站。它控制对任何实用工具的访问,并防止学生使用未经授权的资源。

WebStorm Mac版

WebStorm Mac版

好用的JavaScript开发工具

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

将Eclipse与SAP NetWeaver应用服务器集成。

MinGW - 适用于 Windows 的极简 GNU

MinGW - 适用于 Windows 的极简 GNU

这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

Atom编辑器mac版下载

Atom编辑器mac版下载

最流行的的开源编辑器