内容简介:前言:
前言:
queue() 方法和 dequeue() 方法是为 jQuery 的动画服务的,目的是为了允许一系列动画函数被异步调用,但不会阻塞程序。
所以这篇是为jQuery的动画解析做准备的。
一、 $ .queue()、 $ .dequeue() 和 $() .queue()、 $() .dequeue() 的区别
$().queue() 和
$().dequeue()
这俩是 jQuery.fn.extend() 中的方法,也就是供开发者使用的方法,其内部会分别调用 $.queue() 和 $.dequeue() 方法。
//源码4686行
jQuery.fn.extend( {
queue: function( type, data ) {
xxx
return jQuery.queue( this[ 0 ], type )
},
dequeue: function( type, data ) {
return jQuery.dequeue( this, type )
},
})
(2) $.queue() 和 $.dequeue()
这俩是 jQuery.extend() 中的方法,也就是 jQuery 内部使用的方法。
//源码4594行
jQuery.extend( {
queue: function( elem, type, data ) {},
dequeue: function( elem, type ) {},
})
二、 $ ().queue()
作用1:
作为 setter ,将 function(){} 存进特定队列中。
<div id="A" style="background-color: deeppink">这是A</div>
<script>
function a() {
console.log('a','a34')
}
function b() {
console.log('b','b37')
}
//将a、b方法存在类型为type的队列里
//jQuery.fn.queue 给jQuery对象$("A")
/*setter*/
$("#A").queue('type', a)
$("#A").queue('type', b)
</script>
作用2:
作为 getter ,取出特定队列中 function(){} 的数组。
/*getter*/
$("#A").queue('type') //[a,b]
源码:
jQuery.fn.extend( {
//入队
//源码4663行
//'type', function(){xxx}
queue: function( type, data ) {
var setter = 2;
if ( typeof type !== "string" ) {
data = type;
type = "fx";
setter--;
}
//如果参数小于setter,就执行jQuery.queue()方法
/*这边就是getter*/
if ( arguments.length < setter ) {
//this[0] 目标DOM元素
//type "type"
//返回[function a(){xxx},function b(){xxx}]
return jQuery.queue( this[ 0 ], type );
}
//如果data是undefined就返回jQuery对象
return data === undefined ?
this :
this.each( function() {
/*这边是setter*/
var queue = jQuery.queue( this, type, data );
// Ensure a hooks for this queue
//确保该队列有一个hooks
//返回{empty:{
// 里面是jQuery.Callbacks方法
// 其中add方法被改写
// }}
jQuery._queueHooks( this, type );
/*专门为fx动画做处理*/
if ( type === "fx" && queue[ 0 ] !== "inprogress" ) {
jQuery.dequeue( this, type );
}
} );
},
})
解析:
不涉及 fx 动画的话,本质是调用的内部的 jQuery.queue() 方法
(1)如果不足两个参数的话,就调用 jQuery. queue() 来 get 获取数据。
(2)如果大于等于两个参数的话,就调用 jQuery. queue() 来 set 存数据,并且调用 jQuery._queueHooks() ,用来生成一个 queueHooks 对象或者返回当前值。
(3)如果是 fx 动画,并且队头没有 inprogress 锁的话,就执行 jQuery.dequeue() 方法。
三、jQuery._queueHooks()
作用:
如果目标元素的数据缓存( dataPriv )已存在名称 type + queueHooks 的 Hooks 话,则直接返回该Hooks,
否则返回有 empty 属性的 jQuery.Callback() 方法生成的对象:
其中的 fire() 方法用来清除队列。
源码:
// Not public - generate a queueHooks object, or return the current one
//jQuery内部方法,生成一个queueHooks对象或者返回当前值
//目标元素,"type"
//源码4676行
_queueHooks: function( elem, type ) {
//typequeueHooks
var key = type + "queueHooks";
//如果dataPriv已存在名称typequeueHooks的Hooks话,则直接返回该Hooks
//否则返回有empty属性的jQuery.Callback()方法生成的对象
return dataPriv.get( elem, key ) || dataPriv.access( elem, key, {
empty: jQuery.Callbacks( "once memory" ).add( function() {
dataPriv.remove( elem, [ type + "queue", key ] );
} )
} );
}
解析:
jQuery.Callbacks() 方法会放到 $.dequeue 后讲解
四、jQuery.queue()
作用:
把 callback 依次存入目标元素的 queue 中,或者取出 queue 。
源码:
jQuery.extend( {
//作用:目标元素可执行的任务队列
//源码4596行
//elem 目标元素
//$("#A"),"type",function(){xxx}
queue: function( elem, type, data ) {
var queue;
if ( elem ) {
//typequeue
type = ( type || "fx" ) + "queue";
//从数据缓存中获取typequeue队列,如果没有则为undefined
queue = dataPriv.get( elem, type );
// Speed up dequeue by getting out quickly if this is just a lookup
if ( data ) {
//如果queue不存在,或者data是Array的话
//就创建queue,queue=[data1,data2,...]
if ( !queue || Array.isArray( data ) ) {
queue = dataPriv.access( elem, type, jQuery.makeArray( data ) );
}
//queue存在的话,就把data push进去
else {
queue.push( data );
}
}
//queue=[a,b]
return queue || [];
}
},
})
解析:
(1)作为 setter
function a() {
console.log('a','a34')
}
$("#A").queue('type', a)
此时 data 存在,并且是第一次创建 type='type' 的 queue ,所以使用 dataPriv.access( elem, type, jQuery.makeArray( data ) ) 来创建 queue ,并把 function a push 进 queue 中。
(2)作为 getter
$("#A").queue('type') //[a,b]
此时 data 不存在,直接从数据缓存中获取 queue 并返回。
注意:
jQuery.queue() 始终返回 queue 数组,而 $().queue() 会返回 jQuery 对象或者是 queue 数组。
五、$().dequeue()
作用:
移出队头的函数并执行该 callback 。
源码:
jQuery.fn.extend( {
//出队
//移出队头的函数并执行它
//源码4717行
dequeue: function( type ) {
return this.each( function() {
jQuery.dequeue( this, type );
} );
},
})
解析:
其实就是执行 $.dequeue() 函数。
六、jQuery.dequeue()
作用:
同五。
源码:
jQuery.extend( {
//源码4624行
//目标元素,'type'
dequeue: function( elem, type ) {
//'type'
type = type || "fx";
//get,获取目标元素的队列
var queue = jQuery.queue( elem, type ),
//长度
startLength = queue.length,
//去除对首元素,并返回该元素
fn = queue.shift(),
//确保该队列有一个hooks
hooks = jQuery._queueHooks( elem, type ),
//next相当于dequeue的触发器
next = function() {
jQuery.dequeue( elem, type );
};
// If the fx queue is dequeued, always remove the progress sentinel
//如果fn='inprogress',说明是fx动画队列正在出队,就移除inprogress
if ( fn === "inprogress" ) {
fn = queue.shift();
startLength--;
}
if ( fn ) {
// Add a progress sentinel to prevent the fx queue from being
// automatically dequeued
//如果是fx动画队列的话,就添加inprogress标志,来防止自动出队执行
//意思应该是等上一个动画执行完毕后,再执行下一个动画
if ( type === "fx" ) {
queue.unshift( "inprogress" );
}
// Clear up the last queue stop function
//删除hooks的stop属性方法
delete hooks.stop;
//递归dequeue方法
fn.call( elem, next, hooks );
}
console.log(startLength,'startLength4669')
//如果队列是一个空数组,并且hooks存在的话,清除该队列
if ( !startLength && hooks ) {
console.log('aaaa','bbbb4671')
//进行队列清理
hooks.empty.fire();
}
},
})
解析:
(1) inprogress 应该是一个锁,当 fx 动画执行动画 A 的时候,就加锁,当动画 A 执行完毕后,就解锁,再去运行下一个动画。
(2)注意下 fn.call( elem, next, hooks ) ,保持 fn 的 this 是 element 的同时,给 fn 传的两个参数,分别为 next 和 hooks ,方便操作。
(3)当 queue 是空数组的时候,就触发 hooks.empty 的 fire() 方法,将 queue 清除。
七、jQuery.Callbacks()
作用:
jQuery 的 callbacks 回调方法,返回一个object,里面包含 a、b、c 方法,在执行任意一个方法后,这个方法依旧返回 a、b、c 方法,所以 jQuery.Callbacks() 是链式调用的关键函数。
在 _queueHooks 中有用到该函数:
dataPriv.access( elem, key, {
empty: jQuery.Callbacks( "once memory" ).add( function() {
dataPriv.remove( elem, [ type + "queue", key ] );
} )
} );
源码:
/*创建一个使用以下参数的callback列表
* Create a callback list using the following parameters:
* options:是一个可选的空格分开的参数,它可以改变callback列表的行为或形成新的option对象
* options: an optional list of space-separated options that will change how
* the callback list behaves or a more traditional option object
* 默认情况下一个回调列表会表现成一个event callback列表并且会触发多次
* By default a callback list will act like an event callback list and can be
* "fired" multiple times.
* option可选值:
* Possible options:
* 确保callback列表只会被触发一次,比如Deferred对象
* once: will ensure the callback list can only be fired once (like a Deferred)
* 保持跟踪之前的values,并且会在list用最新的values触发后,调用该回调函数
* 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)
* //确保callback只会被添加一次
* unique: will ensure a callback can only be added once (no duplicate in the list)
* //当callbak返回false时打断调用
* stopOnFalse: interrupt callings when a callback returns false
*
*/
//源码3407行
//callbacks回调对象,函数的统一管理
//once memory
jQuery.Callbacks = function( options ) {
// Convert options from String-formatted to Object-formatted if needed
// (we check in cache first)
options = typeof options === "string" ?
//options: {once:true,memory:true}
createOptions( options ) :
jQuery.extend( {}, options );
//用来知道list是否正被调用
var // Flag to know if list is currently firing
firing,
// Last fire value for non-forgettable lists
memory,
// Flag to know if list was already fired
fired,
// Flag to prevent firing
locked,
// Actual callback list
list = [],
// Queue of execution data for repeatable lists
queue = [],
// Index of currently firing callback (modified by add/remove as needed)
firingIndex = -1,
//触发list中的回调函数
// Fire callbacks
fire = function() {
//true
// Enforce single-firing
//'once memory'中的'once'只允许触发一次
locked = locked || options.once;
// Execute callbacks for all pending executions,
// respecting firingIndex overrides and runtime changes
fired = firing = true;
for ( ; queue.length; firingIndex = -1 ) {
//从queue移除第一个元素,并返回该元素
memory = queue.shift();
while ( ++firingIndex < list.length ) {
// Run callback and check for early termination
//memory=[document, Array(1)]
//memory[0]是document
//意思就是让document去执行add()方法中添加的callback函数
if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&
options.stopOnFalse ) {
// Jump to end and forget the data so .add doesn't re-fire
firingIndex = list.length;
memory = false;
}
}
}
// Forget the data if we're done with it
if ( !options.memory ) {
memory = false;
}
firing = false;
// Clean up if we're done firing for good
//如果once:true,清空list数组
if ( locked ) {
// Keep an empty list if we have data for future add calls
if ( memory ) {
list = [];
// Otherwise, this object is spent
} else {
list = "";
}
}
},
// Actual Callbacks object
self = {
//添加一个回调函数或者是一个回调函数的集合
// Add a callback or a collection of callbacks to the list
add: function() {
if ( list ) {
// If we have memory from a past run, we should fire after adding
if ( memory && !firing ) {
firingIndex = list.length - 1;
queue.push( memory );
}
//闭包
//将arguments作为参数即args传入闭包的add方法中
( function add( args ) {
//args[0]即function(){dataPriv.remove( elem, [ type + "queue", key ] ) }
jQuery.each( args, function( _, arg ) {
if ( isFunction( arg ) ) {
//如果self对象没有该方法,将其push进list中
if ( !options.unique || !self.has( arg ) ) {
list.push( arg );
}
} else if ( arg && arg.length && toType( arg ) !== "string" ) {
// Inspect recursively
add( arg );
}
} );
} )( arguments );
//undefined undefined
if ( memory && !firing ) {
fire();
}
}
//this即self对象
//也就说在调用self对象内的方法后会返回self对象本身
return this;
},
// Remove a callback from the list
remove: function() {
jQuery.each( arguments, function( _, arg ) {
var index;
while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
list.splice( index, 1 );
// Handle firing indexes
if ( index <= firingIndex ) {
firingIndex--;
}
}
} );
return this;
},
// Check if a given callback is in the list.
// If no argument is given, return whether or not list has callbacks attached.
has: function( fn ) {
return fn ?
jQuery.inArray( fn, list ) > -1 :
list.length > 0;
},
// Remove all callbacks from the list
empty: function() {
if ( list ) {
list = [];
}
return this;
},
// Disable .fire and .add
// Abort any current/pending executions
// Clear all callbacks and values
disable: function() {
locked = queue = [];
list = memory = "";
return this;
},
disabled: function() {
return !list;
},
// Disable .fire
// Also disable .add unless we have memory (since it would have no effect)
// Abort any pending executions
lock: function() {
locked = queue = [];
if ( !memory && !firing ) {
list = memory = "";
}
return this;
},
locked: function() {
return !!locked;
},
// Call all callbacks with the given context and arguments
fireWith: function( context, args ) {
if ( !locked ) {
args = args || [];
args = [ context, args.slice ? args.slice() : args ];
queue.push( args );
if ( !firing ) {
fire();
}
}
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 !!fired;
}
};
console.log(queue,'queue3614')
return self;
};
解析:
主要看 add() 和 fire() 方法
self.add()
注意里面的闭包函数,使用闭包的目的是 冻结args的值 ,这样可以避免异步调用造成的值得改变。
add()方法就是将 function() {dataPriv.remove( elem, [ type + "queue", key ] );} push 进 list 数组中,以供 fire() 来调用 list 中的callback。
注意最后返回的是 this ,即 self 对象,也就说在调用 self 对象内的方法后会返回 self 对象本身,而 self 内部又含有 add()、fire() 等方法,通过 jQuery.Callbacks 传入的参数 options 来控制能否调用,及调用的次数。
(2) self.fire()
作用是触发 list 中的回调函数, onece memory 的 once 表示只让 fire() 触发一次后,就需要清理 list, memory 表示是将 list 清空成空数组还是空字符。
八、createOptions()
作用:
将特定格式的string(空格分开),转化为特定格式的 object({xxx:true,xxx:true,...} .
源码:
//将特定格式的string(空格分开),转化为特定格式的object({xxx:true,xxx:true,...})
// Convert String-formatted options into Object-formatted ones
//源码3377行
//'once memory' —> {once:true,memory:true}
function createOptions( options ) {
var object = {};
jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) {
object[ flag ] = true;
} );
return object;
}
解析:
将以空格连接的字符串,以空格拆开,并作为 object 的key,其 value 为 true
比如:
"once memory" => {once:true,memory:true,}
(完)
以上所述就是小编给大家介绍的《jQuery源码解析之$.queue()、$.dequeue()和jQuery.Callbacks()》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- ReactNative源码解析-初识源码
- Spring源码系列:BeanDefinition源码解析
- Spring源码分析:AOP源码解析(下篇)
- Spring源码分析:AOP源码解析(上篇)
- 注册中心 Eureka 源码解析 —— EndPoint 与 解析器
- 新一代Json解析库Moshi源码解析
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Web Design DeMYSTiFieD
Willard, Wendy / 2010-11 / $ 24.86
Website Design just got a whole lot easier! This title helps you to learn the latest website development tools, techniques, and best practices. "Web Design Demystified" provides the hands-on help you ......一起来看看 《Web Design DeMYSTiFieD》 这本书的介绍吧!
JS 压缩/解压工具
在线压缩/解压 JS 代码
RGB HSV 转换
RGB HSV 互转工具