jquery3.0源码解读(四)Callbacks
2016-09-13 20:54
399 查看
本来想先分析defer的,但是在defer的文件中,发现它依赖于另外一个比较重要的模块callbacks。于是,这节就先分析callbacks吧。
钩子
递延
简单来说就是管理回调函数的执行的。这个模块主要还是提供给jquery内部的ajax和defer使用。
可用的 flags:
once: 确保这个回调列表只执行一次
memory: 当队列已经触发之后,再添加进来的函数就会直接被调用(并且使用的是上一次fire的参数),不需要再触发一次。
unique: 保证函数的唯一。
stopOnFalse: 当一个回调返回false 时中断调用
callbacks.disable() 禁用回调列表中的回调
callbacks.disabled() 确定回调列表是否已被禁用。
callbacks.empty() 从列表中删除所有的回调.
callbacks.fire() 用给定的参数调用所有的回调
callbacks.fired() 访问给定的上下文和参数列表中的所有回调。
callbacks.fireWith() 访问给定的上下文和参数列表中的所有回调。
callbacks.has() 确定列表中是否提供一个回调
callbacks.lock() 锁定当前状态的回调列表。
callbacks.locked() 确定回调列表是否已被锁定。
callbacks.remove() 从回调列表中的删除一个回调或回调集合。
下面,我们就直接从构造方法和返回self中提供的操作方法,按照上面的操作方法列表顺序依次分析。
firing:是否正在fire触发阶段,用来判断是外部的触发,还是回调函数内部的嵌套触发
memory:记录上次触发时使用的参数(相当于执行环境)
fired:记录是否已经被触发过至少一次
locked:锁定外部fire相关接口
list:回调列表
queue:多次fire调用(因为可能被嵌套调用)的调用参数列表(相当于执行环境列表)
firingIndex:回调列表list的触发索引,也会用在指定add递延触发位置
还有一个fire内部方法,这个比较重要,它的执行过程如下:
首先,locked = options.once;也就是说,如果flag中有once选项,那么只要执行过fire,下一次就会锁住。
接着,fired = firing = true;标示正在执行fire。
之后,循环从queue中取出执行执行环境,赋值给memory(保存了当前执行环境)。并不断顺序执行列表中的回调函数。期间还判断了stopOnFalse选项。当回调返回false时,并且有stopOnFalse选项,就会销毁memory,相当于memory选项没有了。
再接着,判断options.memory是否定义,如果没有,同样销毁memory(上一次的执行环境)。
最后,判断锁定,如果锁定,外部fire就不用了,由是否有递延指定add(会调用内部fire)是否可用,无递延就要disable掉(locked+list)。
最后,返回self,self中暴露了各种操作方法,如下。
接着,如果有memory(记录着上次触发时使用的参数),并且不在执行的话,保存firingIndex(回调列表list的触发索引,也会用在指定add递延触发位置),并且queue(多次fire调用(因为可能被嵌套调用)的调用参数列表)存入memory。
接着,把add的回调函数,压入list,这里支持递归add。
最后,如果不在firing中,并且是memory模式,则执行fire,由于之前queue中压入了memory,并记录了firingIndex,所以fire会执行刚刚被add进list的回调函数。如果在firing中,当前的函数,自然也会被执行。
http://www.cnblogs.com/haogj/p/4473477.html
http://blog.csdn.net/vbdfforever/article/details/50986673
http://www.cnblogs.com/yangjunhua/p/3509342.html
前置知识
观察者模式钩子
递延
应用场景
在js开发中,由于没有多线程,经常会遇到回调这个概念,比如说,在 ready 函数中注册回调函数,注册元素的事件处理等等。在比较复杂的场景下,当一个事件发生的时候,可能需要同时执行多个回调方法,可以直接考虑到的实现就是实现一个队列,将所有事件触发时需要回调的函数都加入到这个队列中保存起来,当事件触发的时候,从这个队列中依次取出保存的函数并执行。功能说明
callbacks指一个多用途的回调列表对象,提供了强大的的方式来管理回调函数列表。简单的使用方式如下:function fn1( value ){ console.log( value ); } function fn2( value ){ fn1("fn2 says:" + value); return false; } var callbacks = $.Callbacks(); callbacks.add( fn1 ); callbacks.fire( "foo!" ); // outputs: foo! callbacks.add( fn2 ); callbacks.fire( "bar!" ); // outputs: bar!, fn2 says: bar!
简单来说就是管理回调函数的执行的。这个模块主要还是提供给jquery内部的ajax和defer使用。
$.callbacks(flags)
$.callbacks(flags)中的flags是$.Callbacks()的一个可选参数, 结构为一个用空格标记分隔的标志可选列表,用来改变回调列表中的行为 (比如. $.Callbacks( ‘unique stopOnFalse’ ))。可用的 flags:
once: 确保这个回调列表只执行一次
memory: 当队列已经触发之后,再添加进来的函数就会直接被调用(并且使用的是上一次fire的参数),不需要再触发一次。
unique: 保证函数的唯一。
stopOnFalse: 当一个回调返回false 时中断调用
方法说明
callbacks.add() 回调列表中添加一个回调或回调的集合。callbacks.disable() 禁用回调列表中的回调
callbacks.disabled() 确定回调列表是否已被禁用。
callbacks.empty() 从列表中删除所有的回调.
callbacks.fire() 用给定的参数调用所有的回调
callbacks.fired() 访问给定的上下文和参数列表中的所有回调。
callbacks.fireWith() 访问给定的上下文和参数列表中的所有回调。
callbacks.has() 确定列表中是否提供一个回调
callbacks.lock() 锁定当前状态的回调列表。
callbacks.locked() 确定回调列表是否已被锁定。
callbacks.remove() 从回调列表中的删除一个回调或回调集合。
源码分析
源码如下:jQuery.Callbacks = function( options ) { options = typeof options === "string" ? createOptions( options ) : jQuery.extend( {}, options ); var firing, memory, fired, locked, list = [], queue = [], firingIndex = -1, fire = function() { locked = options.once; fired = firing = true; for ( ; queue.length; firingIndex = -1 ) { memory = queue.shift(); while ( ++firingIndex < list.length ) { if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && options.stopOnFalse ) { firingIndex = list.length; memory = false; } } } if ( !options.memory ) { memory = false; } firing = false; if ( locked ) { if ( memory ) { list = []; } else { list = ""; } } }, self = { add: function() { if ( list ) { if ( memory && !firing ) { firingIndex = list.length - 1; queue.push( memory ); } ( function add( args ) { jQuery.each( args, function( _, arg ) { if ( jQuery.isFunction( arg ) ) { if ( !options.unique || !self.has( arg ) ) { list.push( arg ); } } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) { // Inspect recursively add( arg ); } } ); } )( arguments ); if ( memory && !firing ) { fire(); } } return this; }, 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; }, has: function( fn ) { return fn ? jQuery.inArray( fn, list ) > -1 : list.length > 0; }, empty: function() { if ( list ) { list = []; } return this; }, disable: function() { locked = queue = []; list = memory = ""; return this; }, disabled: function() { return !list; }, lock: function() { locked = queue = []; if ( !memory && !firing ) { list = memory = ""; } return this; }, locked: function() { return !!locked; }, fireWith: function( context, args ) { if ( !locked ) { args = args || []; args = [ context, args.slice ? args.slice() : args ]; queue.push( args ); if ( !firing ) { fire(); } } return this; }, fire: function() { self.fireWith( this, arguments ); return this; }, fired: function() { return !!fired; } }; return self; };
下面,我们就直接从构造方法和返回self中提供的操作方法,按照上面的操作方法列表顺序依次分析。
$.callbacks(flags)
取出了options(flag)并保存,并定义了若干参数,分别是:firing:是否正在fire触发阶段,用来判断是外部的触发,还是回调函数内部的嵌套触发
memory:记录上次触发时使用的参数(相当于执行环境)
fired:记录是否已经被触发过至少一次
locked:锁定外部fire相关接口
list:回调列表
queue:多次fire调用(因为可能被嵌套调用)的调用参数列表(相当于执行环境列表)
firingIndex:回调列表list的触发索引,也会用在指定add递延触发位置
还有一个fire内部方法,这个比较重要,它的执行过程如下:
首先,locked = options.once;也就是说,如果flag中有once选项,那么只要执行过fire,下一次就会锁住。
接着,fired = firing = true;标示正在执行fire。
之后,循环从queue中取出执行执行环境,赋值给memory(保存了当前执行环境)。并不断顺序执行列表中的回调函数。期间还判断了stopOnFalse选项。当回调返回false时,并且有stopOnFalse选项,就会销毁memory,相当于memory选项没有了。
再接着,判断options.memory是否定义,如果没有,同样销毁memory(上一次的执行环境)。
最后,判断锁定,如果锁定,外部fire就不用了,由是否有递延指定add(会调用内部fire)是否可用,无递延就要disable掉(locked+list)。
最后,返回self,self中暴露了各种操作方法,如下。
callbacks.add()
首先,判断list(回调函数列表),实现了once功能。在上述fire函数中,如果有once标志,list将被赋值成空。接着,如果有memory(记录着上次触发时使用的参数),并且不在执行的话,保存firingIndex(回调列表list的触发索引,也会用在指定add递延触发位置),并且queue(多次fire调用(因为可能被嵌套调用)的调用参数列表)存入memory。
接着,把add的回调函数,压入list,这里支持递归add。
最后,如果不在firing中,并且是memory模式,则执行fire,由于之前queue中压入了memory,并记录了firingIndex,所以fire会执行刚刚被add进list的回调函数。如果在firing中,当前的函数,自然也会被执行。
callbacks.disable()
这个比较简单,把locked ,queue,list,memory都清空,add将无法使用,fire同样不行。callbacks.disabled()
直接返回!list。callbacks.empty()
清空list 。callbacks.fire()
直接调用了fireWith,并传入了参数。callbacks.fired()
返回!!fired(双感叹号指强制转换成布尔值)。callbacks.fireWith()
判断是否locked,如果不是,把参数格式化成[环境,参数数组],写进queue。并执行fire。callbacks.has()
判断是否有指定回调,无参数则判断回调列表是否空。callbacks.lock()
无递延(每次执行完memory重置为false)或没触发过,则直接禁用;否则还是可以相应add后的递延函数。callbacks.locked()
返回!!locked。callbacks.remove()
移除回调,支持多参数。去掉所有相同回调,当回调内调用remove时,若删除项为已执行项,修正了firingIndex位置。参考
http://www.cnblogs.com/aaronjs/p/3342344.htmlhttp://www.cnblogs.com/haogj/p/4473477.html
http://blog.csdn.net/vbdfforever/article/details/50986673
http://www.cnblogs.com/yangjunhua/p/3509342.html
相关文章推荐
- jQuery.Callbacks 源码解读二
- JQuery3.1.1源码解读(七)【Callbacks】
- jQuery.Callbacks源码解读
- jQuery.Callbacks之源码解读
- [转]jQuery源码解读---执行过程分析
- 读jQuery源码 - Callbacks
- jQuery源码分析之Callbacks方法
- jQuery 2.0.3 源码分析 回调对象 - Callbacks
- 【原创】jQuery1.8.2源码解析之jQuery.Callbacks
- 第二十四课:jQuery.event.remove,dispatch的源码解读
- 【cocos2d-x 3.0】入门样例《SimpleGame》源码解读【3】
- js便签笔记(9)——解读jquery源码时记录的一些知识点
- jQuery源码解读:部份jQuery工具方法实现
- jQuery 1.5 源码解读 - 面向中高阶JSER
- jQuery removeAttr() 源码解读
- jquery源码解析:jQuery工具方法Callbacks详解
- jQuery源码解读 - 数据缓存系统:jQuery.data
- jquery1.8.1源码解读
- jQuery 1.5 源码解读 面向中高阶JSER
- jQuery 2.0.3 源码分析 回调对象 - Callbacks