博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
jQuery1.9.1源码分析--Callbacks对象
阅读量:5296 次
发布时间:2019-06-14

本文共 12815 字,大约阅读时间需要 42 分钟。

 
1 var optionsCache = {};  2   3     /*  4      根据字符串格式的参数创建对象的键值对象,  5      并且返回一个object变量存储已经存在的key参数,且value值为true,  6      与optionsCache引用同一个对象  7      */  8   9     function createOptions(options) { 10         var object = optionsCache[options] = {}; 11         jQuery.each(options.match(core_rnotwhite) || [], function (_, flag) { 12             object[flag] = true; 13         }); 14         return object; 15     } 16  17     /* 18      * Create a callback list using the following parameters: 19      * 20      *    options: an optional list of space-separated options that will change how 21      *            the callback list behaves or a more traditional option object 22      * 23      * By default a callback list will act like an event callback list and can be 24      * "fired" multiple times. 25      * 26      * Possible options: 27      * 28      *    once:            will ensure the callback list can only be fired once (like a Deferred) 29      *    确保这个回调列表只执行一次. 30      * 31      *    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) 32      * 当回调列表已经被触发调用了,我们再给列表添加回调的时候将会执行该回调 33      * 34      *    unique:            will ensure a callback can only be added once (no duplicate in the list) 35      * 确保一个回调再列表中只会被添加一次(即列表不能有重复的回调). 36      * 37      *    stopOnFalse:    interrupt callings when a callback returns false 38      * 当一个回调返回false 时中断调用 39      */ 40     jQuery.Callbacks = function (options) { 41         // 将options字符串格式转换为对象格式 42         // 先检查是否已有缓存 43         options = typeof options === 'string' ? 44             (optionsCache[options] || createOptions(options)) : 45             jQuery.extend({}, options); 46  47         var 48         // 用来标识列表是否正在触发 49             firing, 50         // 上一次触发的值 (备忘列表) 51             memory, 52         // 列表已被触发的标识 53             fired, 54         // 回调列表的长度 55             firingLength, 56         // 当前触发的回调索引值 57             firingIndex, 58         // 第一个要触发的回调函数 59         // (used internally by add and fireWith) 60             firingStart, 61         // 回调列表 62             list = [], 63         // 可重复的回调函数堆栈,用于控制触发回调时的参数列表 64             // flags不能为once 65             stack = !options.once && [], 66         // 触发回调方法,结束了当前队列, 67         // 如果还有其他等待队列,则也触发 68             fire = function (data) { 69                 // 如果flags包含memory,则记录data 70                 // 值是一个数组第一个元素是fireWith的context对象,第二个则是fire方法的参数伪数组 71                 memory = options.memory && data; 72                 // 标记已触发 73                 fired = true; 74                 firingIndex = firingStart || 0; 75                 firingStart = 0; 76                 firingLength = list.length; 77                 // 标记正在触发回调 78                 firing = true; 79                 // 遍历回调列表 80                 for (; list && firingIndex < firingLength; firingIndex++) { 81                     if (list[firingIndex].apply(data[0], data[1]) === false && options.stopOnFalse) { 82                         // 强制将memory设置为false 83                         // 阻止未来可能由于add所产生的回调 84                         memory = false; 85                         //由于参数stopOnFalse为true,所以当有回调函数返回值为false时退出循环 86                         break; 87                     } 88                 } 89                 // 标记回调结束 90                 firing = false; 91                 // 如果列表存在 92                 if (list) { 93                     // 如果堆栈存在(非once的情况) 94                     if (stack) { 95                         // 如果堆栈不为空 96                         if (stack.length) { 97                             // 从堆栈头部取出,递归fire 98                             fire(stack.shift()); 99                         }100 101                         // 否则,如果有记忆(memory && ((once && unique) || once))102                     } else if (memory) {103                         // 列表清空104                         list = [];105 106                         // 再否则阻止回调列表中的回调 (once || (once && unique))107                     } else {108                         self.disable();109                     }110                 }111             },112         // 暴露在外的Callbacks对象113             self = {114                 /**115                  * 回调列表中添加一个回调或回调的集合。116                  * {arguments} 一个函数,或者一个函数数组用来添加到回调列表117                  * @returns {*}118                  */119                 add: function () {120                     if (list) {121                         // 首先存储当前列表长度122                         var start = list.length;123                         (function add(args) {124                             jQuery.each(args, function (_, arg) {125                                 var type = jQuery.type(arg);126                                 // 如果是函数127                                 if (type === 'function') {128                                     // 确保是否可以重复或者没有该回调129                                     if (!options.unique || !self.has(arg)) {130                                         list.push(arg);131                                     }132 133                                     // 如果是类数组或对象134                                 } else if (arg && arg.length && type !== 'string') {135                                     // 递归136                                     add(arg);137                                 }138                             });139                         })(arguments);140 141                         // 如果正在回调就将回调时的循环结尾变成现有长度142                         if (firing) {143                             firingLength = list.length;144 145                             // 否则如果有memory,我们立刻调用146                             // 前面至少有一次fire,这样memory才会有值147                         } else if (memory) {148                             firingStart = start;149                             fire(memory);150                         }151                     }152 153                     return this;154                 },155                 /*156                  删除回调或回调回调列表的集合157                  */158                 remove: function () {159                     if (list) {160                         jQuery.each(arguments, function (_, arg) {161                             var index;162                             // 找到arg在列表中的位置163                             while ((index = jQuery.inArray(arg, list, index)) > -1) {164                                 // 根据得到的位置删除列表中的回调函数165                                 list.splice(index, 1);166 167                                 // 如果正在回调过程中,则调整循环的索引和长度168                                 // 继续下次循环169                                 if (firing) {170                                     if (index <= firingLength) {171                                         firingLength--;172                                     }173                                     if (index <= firingIndex) {174                                         firingIndex--;175                                     }176                                 }177                             }178                         });179                     }180 181                     return this;182                 },183                 // 回调函数是否在列表中184                 has: function (fn) {185                     return fn ? jQuery.inArray(fn, list) > -1 : !!(list && list.length);186                 },187                 // 从列表中删除所有回调函数188                 empty: function () {189                     list = [];190                     return this;191                 },192                 /*193                  禁用回调列表中的回调194                  */195                 disable: function () {196                     list = stack = memory = undefined;197                     return this;198                 },199                 // 判断是否被禁用了200                 disabled: function () {201                     return !list;202                 },203                 // 锁定列表204                 lock: function () {205                     stack = undefined;206                     if (!memory) {207                         self.disable();208                     }209                     return this;210                 },211                 locked: function () {212                     return !stack;213                 },214                 /**215                  * 以给定的上下文和参数调用所有回调函数216                  * @param context 上下文217                  * @param args218                  * @returns {*}219                  */220                 fireWith: function (context, args) {221                     args = args || [];222                     args = [context, args.slice ? args.slice() : args];223 224                     if (list && (!fired || stack)) {225                         // 如果正在回调226                         if (firing) {227                             // 将参数推入堆栈,等待当前回调结束再调用228                             stack.push(args);229 230                             // 否则直接调用231                         } else {232                             fire(args);233                         }234                     }235 236                     return this;237                 },238                 // 以给定的参数调用所有回调函数239                 fire: function () {240                     self.fireWith(this, arguments);241                     return this;242                 },243                 // 回调列表是否被触发过244                 fired: function () {245                     return !!fired;246                 }247             };248 249         return self;250     };
View Code
 

 

 

用法:

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!可用的 flags: once: 确保这个回调列表只执行一次(像一个递延 Deferred). memory: 保持以前的值和将添加到这个列表的后面的最新的值立即执行调用任何回调 (像一个递延 Deferred). unique: 确保一次只能添加一个回调(所以有没有在列表中的重复). stopOnFalse: 当一个回调返回false 时中断调用 默认情况下,回调列表将像事件的回调列表中可以多次触发。如何在理想情况下应该使用的flags的例子,见下文:$.Callbacks( 'once' ):var callbacks = $.Callbacks( "once" );callbacks.add( fn1 );callbacks.fire( "foo" );callbacks.add( fn2 );callbacks.fire( "bar" );callbacks.remove( fn2 );callbacks.fire( "foobar" );/*output: foo*/$.Callbacks( 'memory' ):var callbacks = $.Callbacks( "memory" );callbacks.add( fn1 );callbacks.fire( "foo" );callbacks.add( fn2 );callbacks.fire( "bar" );callbacks.remove( fn2 );callbacks.fire( "foobar" );/*output:foofn2 says:foobarfn2 says:barfoobar*/$.Callbacks( 'unique' ):var callbacks = $.Callbacks( "unique" );callbacks.add( fn1 );callbacks.fire( "foo" );callbacks.add( fn1 ); // repeat additioncallbacks.add( fn2 );callbacks.fire( "bar" );callbacks.remove( fn2 );callbacks.fire( "foobar" );/*output:foobarfn2 says:barfoobar*/$.Callbacks( 'stopOnFalse' ):function fn1( value ){    console.log( value );    return false;}function fn2( value ){    fn1("fn2 says:" + value);    return false;}var callbacks = $.Callbacks( "stopOnFalse");callbacks.add( fn1 );callbacks.fire( "foo" );callbacks.add( fn2 );callbacks.fire( "bar" );callbacks.remove( fn2 );callbacks.fire( "foobar" );/*output:foobarfoobar*/因为$.Callbacks() 支持一个列表的flags而不仅仅是一个,设置几个flags,有一个累积效应,类似“&&”。这意味着它可能结合创建回调名单,unique 和确保如果名单已经触发,将有更多的回调调用最新的触发值 (i.e.$.Callbacks("unique memory")).  $.Callbacks( 'unique memory' ):function fn1( value ){    console.log( value );    return false;}function fn2( value ){    fn1("fn2 says:" + value);    return false;}    var callbacks = $.Callbacks( "unique memory" );callbacks.add( fn1 );callbacks.fire( "foo" );callbacks.add( fn1 ); // repeat additioncallbacks.add( fn2 );callbacks.fire( "bar" );callbacks.add( fn2 );callbacks.fire( "baz" );callbacks.remove( fn2 );callbacks.fire( "foobar" );/*output:foofn2 says:foobarfn2 says:barbazfn2 says:bazfoobar*/使用Callbacks实现的观察者模式:var topics = {};jQuery.Topic = function( id ) {    var callbacks,        method,        topic = id && topics[ id ];    if ( !topic ) {        callbacks = jQuery.Callbacks();        topic = {            publish: callbacks.fire,            subscribe: callbacks.add,            unsubscribe: callbacks.remove        };        if ( id ) {            topics[ id ] = topic;        }    }    return topic;};// Subscribers$.Topic( "mailArrived" ).subscribe( fn1 );$.Topic( "mailArrived" ).subscribe( fn2 );$.Topic( "mailSent" ).subscribe( fn1 );// Publisher$.Topic( "mailArrived" ).publish( "hello world!" );$.Topic( "mailSent" ).publish( "woo! mail!" );// Here, "hello world!" gets pushed to fn1 and fn2// when the "mailArrived" notification is published// with "woo! mail!" also being pushed to fn1 when// the "mailSent" notification is published. /*output:hello world!fn2 says: hello world!woo! mail!*/

 

转载于:https://www.cnblogs.com/webFrontDev/archive/2013/05/13/3076040.html

你可能感兴趣的文章
Java Session 介绍;
查看>>
spoj TBATTLE 质因数分解+二分
查看>>
Django 模型层
查看>>
dedecms讲解-arc.listview.class.php分析,列表页展示
查看>>
Extjs6 经典版 combo下拉框数据的使用及动态传参
查看>>
【NodeJS】http-server.cmd
查看>>
研磨JavaScript系列(五):奇妙的对象
查看>>
面试题2
查看>>
selenium+java iframe定位
查看>>
P2P综述
查看>>
第五章 如何使用Burp Target
查看>>
Sprint阶段测试评分总结
查看>>
sqlite3经常使用命令&amp;语法
查看>>
linux下编译openjdk8
查看>>
【python】--迭代器生成器装饰器
查看>>
Pow(x, n)
查看>>
安卓当中的线程和每秒刷一次
查看>>
MySQL Proxy
查看>>
随机颜色值
查看>>
每日一库:Modernizr.js,es5-shim.js,es5-safe.js
查看>>