内容简介:前言:
前言:
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源码解析
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
锋利的jQuery
单东林、张晓菲、魏然 / 人民邮电出版社 / 2009-6 / 39.00元
《锋利的jQuery》循序渐进地对jQuery的各种函数和方法调用进行了介绍,读者可以系统地掌握jQuery的DOM操作、事件监听和动画、表单操作、AJAX以及插件方面等知识点,并结合每个章节后面的案例演示进行练习,达到掌握核心知识点的目的。为使读者更好地进行开发实践,《锋利的jQuery》的最后一章将前7章讲解的知识点和效果进行了整合,打造出一个非常有个性的网站,并从案例研究、网站材料、网站结构......一起来看看 《锋利的jQuery》 这本书的介绍吧!