关键词:
callbacks是jquery的核心之一。
语法如下:
jQuery.Callbacks( flags ) flags 类型: String 一个用空格标记分隔的标志可选列表,用来改变回调列表中的行为。
once
: 确保这个回调列表只执行( .fire() )一次(像一个递延 Deferred).
memory
: 保持以前的值,将添加到这个列表的后面的最新的值立即执行调用任何回调 (像一个递延 Deferred).
unique
: 确保一次只能添加一个回调(所以在列表中没有重复的回调).
stopOnFalse
: 当一个回调返回false 时中断调用
使用案例:
function fn1(val) { console.log(‘fn1 says ‘ + val); } function fn2(val) { console.log(‘fn2 says ‘ + val); return false; } var cbs = $.Callbacks(‘once memory‘); cbs.add(fn1); //第一次fire会缓存传入的参数 cbs.fire(‘foo‘); //fn1 says foo //fire过一次之后,以后的add都会自动调用fire,传入的参数是上次fire传入的‘foo‘ cbs.add(fn2); //fn2 says foo
function fn1(val) { console.log(‘fn1 says ‘ + val); } function fn2(val) { console.log(‘fn2 says ‘ + val); return false; } var cbs = $.Callbacks(‘stopOnFalse‘); cbs.add(fn2) cbs.add(fn1); cbs.fire(‘foo‘); //fn2 says foo
function fn1(val) { console.log(‘fn1 says ‘ + val); } function fn2(val) { console.log(‘fn2 says ‘ + val); return false; } var cbs = $.Callbacks(‘once‘); cbs.add(fn2) cbs.add(fn1); cbs.fire(‘foo‘); //fn2 says foo fn1 says foo cbs.add(fn2); cbs.fire("bar"); //不输出
源码分析:
var optionsCache = {}; // Convert String-formatted options into Object-formatted ones and store in cache //20170618 huanhua 参数options="once memory" // 返回结果: optionsCache[once memory]={once:true,memory:true} function createOptions( options ) { var object = optionsCache[options] = {}; //20170618 huanhua 前面已经定义正则 core_rnotwhite= /S+/g , options.match( core_rnotwhite )返回数组["once","memory"]类似这种 jQuery.each( options.match( core_rnotwhite ) || [], function( _, flag ) { object[ flag ] = true; }); return object; } /* * Create a callback list using the following parameters: * * options: an optional list of space-separated options that will change how * the callback list behaves or a more traditional option object * * By default a callback list will act like an event callback list and can be * "fired" multiple times. * * Possible options: * * once: will ensure the callback list can only be fired once (like a Deferred) * * 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) * * unique: will ensure a callback can only be added once (no duplicate in the list) * * stopOnFalse: interrupt callings when a callback returns false * */ jQuery.Callbacks = function( options ) { // Convert options from String-formatted to Object-formatted if needed // (we check in cache first) options = typeof options === "string" ? ( optionsCache[ options ] || createOptions( options ) ) : jQuery.extend( {}, options ); var // Flag to know if list is currently firing firing, // Last fire value (for non-forgettable lists) //20170618 huanhua 存储的是最后一次 fire传递的参数值 memory, // Flag to know if list was already fired fired, // End of the loop when firing firingLength, // Index of currently firing callback (modified by remove if needed) firingIndex, // First callback to fire (used internally by add and fireWith) firingStart, // Actual callback list // 20170618 huanhua 回调函数的存储列表 list = [], // Stack of fire calls for repeatable lists // 20170618 huanhua 回调函数不是只执行一次的时候,用 stack保存正在执行回调的时候,再次请求执行的 fire()中传入的参数 stack = !options.once && [], // Fire callbacks fire = function (data) {//20170618 data是一个数组[context,arg],第一个是执行的上下午,第二个是真正的参数 memory = options.memory && data; fired = true; firingIndex = firingStart || 0; firingStart = 0; firingLength = list.length; firing = true; for (; list && firingIndex < firingLength; firingIndex++) { //20170618 huanhua 判断 if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) { // 阻止未来可能由于add所产生的回调,add中有这段代码 //else if ( memory ) { // firingStart = start; //20170618 huanhua 从列表最新添加的回调函数位置开始执行 // fire( memory ); //20170618 huanhua 立即执行回调函数 //} memory = false; // To prevent further calls using add break;//由于参数stopOnFalse为true,所以当有回调函数返回值为false时退出循环 } } firing = false; if (list) { //20170618 huanhua 处理正在执行回调中,再次触发的 fire(),也就是同时第一个触发的 fire还没执行完,紧接着多次执行了 fire if ( stack ) { if ( stack.length ) { fire( stack.shift() ); } } else if ( memory ) { list = []; } else { self.disable(); } } }, // Actual Callbacks object self = { // Add a callback or a collection of callbacks to the list add: function() { if ( list ) { // First, we save the current length var start = list.length; (function add(args) { //20170618 huanhua add(fun1,fun2,fun3) jQuery.each( args, function( _, arg ) { var type = jQuery.type(arg); //20170618 huanhua 判断是函数 if (type === "function") { //20170618 huanhua !options.unique判断 当$.Callbacks(‘unique‘)时,保证列表里面不会出现重复的回调 //!self.has( arg )只要不列表里不存在,就添加到列表 if ( !options.unique || !self.has( arg ) ) { list.push( arg ); } //20170618 huanhua 判断传递的参数是类似数组的对象,或者就是数组 // add({leng:2,0:fun1,1:fun2},{leng:1,0:fun3}); } else if ( arg && arg.length && type !== "string" ) { // Inspect recursively add( arg ); } }); })( arguments ); // Do we need to add the callbacks to the // current firing batch? //20170618 huanhua 当fire执行的时间需要比较长的时候,我们在执行 add的时候,fire也在执行,add执行完后,fire还没执行完,为了防止新加的不执行, //所以重新赋值了需要执行的回调函数个数 firingLength = list.length; if ( firing ) { firingLength = list.length; // With memory, if we‘re not firing then // we should call right away //20170618 huanhuaa $.CallBacks("memory"),并且还调用了 fire } else if ( memory ) { firingStart = start; //20170618 huanhua 从列表最新添加的回调函数位置开始执行 fire( memory ); //20170618 huanhua 立即执行回调函数 } } return this; }, // Remove a callback from the list //20170618 huanhua 删除指定的回调函数 remove: function () { //20170618 huanhua 判断回调函数列表是有效的 if ( list ) { jQuery.each( arguments, function( _, arg ) { var index; //20170618 huanhua index = jQuery.inArray( arg, list, index )获取需要被删除的回调函数在列表中的位置 while ((index = jQuery.inArray(arg, list, index)) > -1) { //20170618 huanhua 删除回调函数 list.splice( index, 1 ); // Handle firing indexes //20170618 huanhua 如果删除的时候在执行 fire() if (firing) { //20170618 huanhua 当被删除的回调函数的位置 <= 回调函数列表总长度的时候,删除了一个回调函数,所以 firingLength 要减一个了 if ( index <= firingLength ) { firingLength--; } //20170618 huanhua 当被删除的回调函数的位置 <= 执行到的回调函数的位置时候,删除了一个回调函数,所以 firingIndex 要减一个了 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) {//回调函数是否在列表中. //20170616 huanhua !!( list && list.length ) 如果执行的 has("")/has(undefined)等等,如果 执行了 def.disable(),list就等于undefined了 return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length ); }, // Remove all callbacks from the list //20170618 huanhua 清空回调函数列表 empty: function() { list = []; return this; }, // Have the list do nothing anymore //20170618 huanhua 禁用回调列表中的回调。 disable: function() { list = stack = memory = undefined; return this; }, // Is it disabled? disabled: function() { return !list; }, // Lock the list in its current state lock: function() { stack = undefined; if ( !memory ) { self.disable(); } return this; }, // Is it locked? locked: function() { return !stack; }, // Call all callbacks with the given context and arguments fireWith: function( context, args ) { args = args || []; args = [ context, args.slice ? args.slice() : args ]; if (list && (!fired || stack)) { //20170618 huanhua 如果正在执行回调函数 //将参数推入堆栈,等待当前回调结束再调用 if ( firing ) { stack.push(args); //20170618 huanhua 如果当前不是正在执行回调函数,就直接执行 } else { fire( args ); } } 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; } }; return self; };
join()方法之我见
JavaScriptjoin()方法定义和用法join()方法用于把数组中的所有元素放入一个字符串。元素是通过指定的分隔符进行分隔的。语法arrayObject.join(separator)参数描述separator可选。指定要使用的分隔符。如果省略该参数,则使用逗号作为分... 查看详情
fec之我见三
...文讲解:3)标准的RTP头结构如下所示:其中第一个字节中的x标志位是否扩展了RTP头,RTP协议允许用户自定义的扩展,扩展的字段紧挨上述RTP固定头。RTP扩展投中承载如下信息:1).当前包所在的Group组序号,码流由连续的Group组成... 查看详情
架构师之我见
...朋友也可以留言,我们共同探讨这个话题。 架构师之我见 2009-08-06架构 查看详情
闭包之我见
一、闭包是什么? · 闭包就是可以使得函数外部的对象能够获取函数内部的信息。 ·闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。... 查看详情
前端之我见(代码片段)
1.HTML介绍1.1服务器本质1importsocket234sk=socket.socket()56sk.bind(("127.0.0.1",8080))7sk.listen(5)8910whileTrue:11conn,addr=sk.accept()12data=conn.recv(8096)13conn.send(b"HTTP/1.1200OK\\r\\n\\r\\n")14conn.s 查看详情
httphelper之我见
前几月一直用一个Http的访问类去调用WebApi,说句实话最开始没觉有什么,一是技术老,二是觉得比较简单,但是最近我一直关注云开发和AI这块儿微软技术,看到云平台调用API大多类似,所以回想这个早年的调... 查看详情
我之我见:ftp共享
目录1.ftp服务概述...11.1简介...11.2复合TCP连接...11.3数据连接模式...11.3.1主动模式...11.3.2被动模式...11.4数据传输模式...11.5ftp类型...12.部署ftp.22.1安装ftp.22.2ftp功能划分...22.2.1ftp访问控制...22.2.2ftp连接及传输控制...22.2.3ftp上传文件默... 查看详情
关于元素居中之我见(干货)
不使用定位 水平居中:text-align=center;(可继承) 竖直居中:margin:0auto;(块级元素) 其他居中:1.文字居中:父元素设置高子元素设置高 line-height=height(父元素) 2.图片居中: ... 查看详情
fec之我见一
顾名思义,FEC前向纠错,根据收到的包进行计算获取丢掉的包,而和大神沟通的结果就是纠错神髓:收到的媒体包+冗余包>=原始媒体包数据 直到满足 收到的媒体包+ 冗余包>=原始媒体包数据 ... 查看详情
关于堆栈和block之我见
临时变量存在栈里对象存在堆里关于blockc与oc最大的区别在于一个是静态语言一个是动态语言先看看c的写法voidtestFunc(){printf("helloworld");}voidtestFuncPoint(void){void(*x)(void)=testFunc;x();} c语言没有block一说,叫做函数指针,其实现... 查看详情
classpathxmlapplicationcontext源代码阅读之我见
由于本人的能力有限,只能说出自己的见解,如有错漏什么的,请大家批评指出。由于代码封装太多,这里只列出了我认为的部分最重要的代码,一些简单的封装代码,不在下面列出。由于代码太过于复杂,在本次博客中,只列... 查看详情
编译原理之我见
经过网上的调查,我发现编译原理并不像我所想象的那样简单,我以为编译原理其实就是像塑造一个翻译师一样,赋予它翻译的架构即可,但是经过调查后,结果却不是我所想,编译原理就是将高级语言翻... 查看详情
我之我见:samba共享
目录1.Samba概述11.1Samba简介11.2SMB/CIFS协议11.3Samba服务基础11.3.1主要软件包11.3.2系统服务脚本11.4共享账号控制11.4.1共享访问控制11.4.2共享账号管理22.配置Samba服务器22.1服务器端操作32.1.1安装samba服务器端程序32.1.2建立samba认证用户nic... 查看详情
依赖倒置之我见
.net程序员对面向对象设计原则以及设计模式的重视似乎不如Java,包括许多有经验.net的程序员,也并没有将面向对象的思想渗透进项目中。我本身就是这样一个例子。C#和Java都是面向对象的语言,设计模式对两者是通用的,... 查看详情
云服务之我见
说实话,虽然工作了十几年,但是很少写东西,今后努力多写的东西,记录一下这几年在it领域工作的一些心得,来和大家一起分享!首先说一下笔者工作的是一个二三线城市,有幸进入了一家云计算的工作,不过主营业务并不... 查看详情
margin,padding之我见
在网页布局中,margin和padding绝对会占很重要的作用,但是在实际的项目中,很多新手前端程序员们往往不能正确的使用它们,导致会出现一些不必要的麻烦,下面是我在前几天的项目中遇到的一些问题,以及个人总结的一... 查看详情
fec之我见四
接上文,来详细的说明一下FEC前向纠错的具体实现:FEC_matrix是一个比较常用的算法,Vandermonde,范德蒙矩阵是法国数学家范德蒙提出的一种各列为几何级数的矩阵。范德蒙矩阵的定义:V=其第i行、第j列可以表示为(αi)^(j-1)。范... 查看详情
快应用之我见
为了对抗微信小程序,安卓手机厂商联合起来推出了快应用,这是好事一件,但快应用的实现方式在我看来并不是一个最佳的方案。首先,既然是对抗小程序,就不应该学小程序的那一套类似于Vue的开发框架,而应该采用React框... 查看详情