• 自己动手实现 jQuery Callbacks


    最近大量的用到jQuery Callbacks 对象,jQuery库中的$.ajax()和$.Deferred() 对象也是基于这个对象实现,中午不困, 利用这点时间片自己动手模拟实现了这个对象的部分功能(没有100%完全测试), 以加深理解:

    用法和$.Callbacks完全一致 , 但是只是实现了add , remove , fire , empty, has和带参数的构造函数功能,  $.Callbacks 还有disable,disabled, fireWith , fired , lock, locked 方法

     代码如下: 

      1  String.prototype.trim = function ()
      2         {
      3             return this.replace( /^\s+|\s+$/g, '' );
      4         };
      5 
      6         // Simulate jQuery.Callbacks object
      7         function MyCallbacks( options )
      8         {
      9             var ops = { once: false, memory: false, unique: false, stopOnFalse: false };
     10 
     11             if ( typeof options === 'string' && options.trim() !== '' )
     12             {
     13                 var opsArray = options.split( /\s+/ );
     14                 for ( var i = 0; i < options.length; i++ )
     15                 {
     16                     if ( opsArray[i] === 'once' )
     17                         ops.once = true;
     18                     else if ( opsArray[i] === 'memory' )
     19                         ops.memory = true;
     20                     else if ( opsArray[i] === 'unique' )
     21                         ops.unique = true;
     22                     else if ( opsArray[i] === 'stopOnFalse' )
     23                         ops.stopOnFalse = true;
     24                 }
     25             }
     26 
     27             var ar = [];
     28             var lastArgs = null;
     29             var firedTimes = 0;
     30 
     31             function hasName( name )
     32             {
     33                 var h = false;
     34 
     35                 if ( typeof name === 'string'
     36                     && name !== null
     37                     && name.trim() !== ''
     38                     && ar.length > 0 )
     39                 {
     40                     for ( var i = 0; i < ar.length; i++ )
     41                     {
     42                         if ( ar[i].name === name )
     43                         {
     44                             h = true;
     45                             break;
     46                         }
     47                     }
     48                 }
     49 
     50                 return h;
     51             }
     52 
     53             // add a function
     54             this.add = function ( fn )
     55             {
     56                 if ( typeof fn === 'function' )
     57                 {
     58                     if ( ops.unique )
     59                     {
     60                         // check whether it had been added before
     61                         if ( fn.name !== '' && hasName( fn.name ) )
     62                         {
     63                             return this;
     64                         }
     65                     }
     66 
     67                     ar.push( fn );
     68 
     69                     if ( ops.memory )
     70                     {
     71                         // after added , call it immediately
     72                         fn.call( this, lastArgs );
     73                     }
     74                 }
     75 
     76                 return this;
     77             };
     78 
     79             // remove a function
     80             this.remove = function ( fn )
     81             {
     82                 if ( typeof ( fn ) === 'function'
     83                     && fn.name !== ''
     84                     && ar.length > 0 )
     85                 {
     86                     for ( var i = 0; i < ar.length; i++ )
     87                     {
     88                         if ( ar[i].name === fn.name )
     89                         {
     90                             ar.splice( i, 1 );
     91                         }
     92                     }
     93                 }
     94 
     95                 return this;
     96             };
     97 
     98             // remove all functions 
     99             this.empty = function ()
    100             {
    101                 ar.length = 0;
    102                 return this;
    103             };
    104 
    105             // check whether it includes a specific function
    106             this.has = function ( fn )
    107             {
    108                 var f = false;
    109 
    110                 if ( typeof ( fn ) === 'function'
    111                     && fn.name !== ''
    112                     && ar.length > 0 )
    113                 {
    114                     for ( var i = 0; i < ar.length; i++ )
    115                     {
    116                         if ( ar[i].name === fn.name )
    117                         {
    118                             f = true;
    119                             break;
    120                         }
    121                     }
    122                 }
    123 
    124                 return f;
    125             };
    126 
    127             // invoke funtions it includes one by one 
    128             this.fire = function ( args )
    129             {
    130                 if ( ops.once && firedTimes > 0 )
    131                 {
    132                     return this;
    133                 }
    134 
    135                 if ( ar.length > 0 )
    136                 {
    137                     var r;
    138 
    139                     for ( var i = 0; i < ar.length; i++ )
    140                     {
    141                         r = ar[i].call( this, args );
    142 
    143                         if ( ops.stopOnFalse && r === false )
    144                         {
    145                             break;
    146                         }
    147                     }
    148                 }
    149 
    150                 firedTimes++;
    151 
    152                 if ( ops.memory )
    153                 {
    154                     lastArgs = args;
    155                 }
    156 
    157                 return this;
    158             };
    159         };

     测试函数如下:(注意fn1 fn2是匿名函数, fn2返回false , fn3是有“名”函数)

           var fn1 = function ( v )
            {
                console.log( 'fn1 ' + ( v || '' ) );
            };
    
            var fn2 = function ( v )
            {
                console.log( 'fn2 ' + ( v || '' ) );
                return false;
            };
    
            function fn3( v )
            {
                console.log( 'fn3 ' + ( v || '' ) );
            };

    1 . 测试add & fire

    var cb=new MyCallbacks();

    cb.add(fn1)

    cb.add(fn2)

    cb.add(fn3)

    cb.fire('hello') 

    输出: 

    fn1 hello
    fn2 hello
    fn3 hello
     
    2.测试remove 

    var cb=new MyCallbacks();

    cb.add(fn1)

    cb.add(fn2)

    cb.add(fn3)

    cb.remove(fn1)
    cb.fire('hello')
    cb.remove(fn3)
    cb.fire('hello')

    输出: 

    fn1 hello
    fn2 hello
    fn3 hello
    ----------------------------
    fn1 hello
    fn2 hello
     
    2.测试has

    var cb=new MyCallbacks();

    cb.add(fn1)

    cb.add(fn2)

    cb.add(fn3)

    cb.has(fn1)  

    cb.has(fn3)  

    输出: 

    false

    ---------------

    true

    3.测试带参数的构造函数 : once

    var cb=new MyCallbacks('once')

    cb.add(fn1)

    cb.fire('hello')

    cb.fire('hello')

    cb.add(fn2)

    cb.fire('hello')

    输出:

    hello 

    -------------------

    ------------------

    ------------------------------

    4.测试带参数的构造函数 : memory

     var cb=new MyCallbacks('memory')

    cb.add(fn1)

    cb.fire('hello') // 输出 : fn1 hello

    cb.add(fn2) // 输出 : fn2 hello

    cb.fire('hello') 

     输出 :

     fn1 hello

     fn2 hello

    5.测试带参数的构造函数 : stopOnFalse

    var cb=new MyCallbacks('stopOnFalse')

    cb.add(fn1)

    cb.add(fn2)

    cb.add(fn3)

    cb.fire('hello')

    输出:

    fn1 hello
    fn2 hello

    6.测试带参数的构造函数 :unique

    var cb=new MyCallbacks('unique')

    b.add(fn3)

    b.add(fn3)

    cb.fire('hello')

    输出:

    fn3 hello

    7. 测试带组合参数的构造函数:四个设置参数可以随意组合,一下只测试全部组合的情况, 不然要写16个测试用例 T_T

    var cb=new MyCallbacks('once memory unique stopOnFalse')

    cb.add(fn1) // 输出: fn1

    cb.add(fn2) // 输出: fn2

    cb.add(fn3) //  输出: fn3

    cb.fire('hello') 

    输出: 

    fn1 hello
    fn2 hello

    cb.fire('hello') // 输出:没有输出

    以下是官方API 文档:

    Description: A multi-purpose callbacks list object that provides a powerful way to manage callback lists.The $.Callbacks() function is internally used to provide the base functionality behind the jQuery $.ajax() and$.Deferred() components. It can be used as a similar base to define functionality for new components.

    构造函数 : jQuery.Callbacks( flags )

    flags
    Type: String
    An optional list of space-separated flags that change how the callback list behaves.

    Possible flags:

    • once: Ensures the callback list can only be fired once (like a Deferred).
    • memory: Keeps 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: Ensures a callback can only be added once (so there are no duplicates in the list).
    • stopOnFalse: Interrupts callings when a callback returns false.

    By default a callback list will act like an event callback list and can be "fired" multiple times.

    Two specific methods were being used above: .add() and .fire(). The .add() method supports adding new callbacks to the callback list, while the .fire() method executes the added functions and provides a way to pass arguments to be processed by the callbacks in the same list.

    利用Callbacks 实现发布订阅模式 pub/sub: (官方文档)

      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;
            };
     使用 
        $.Topic( 'mailArrived' ).subscribe( function ( e )
            {
                console.log( 'Your have new email! ' );
                console.log( "mail title : " + e.title );
                console.log( "mail content : " + e.content );
            }
            );
    
            $.Topic( 'mailArrived' ).publish( { title: 'mail title', content: 'mail content' } );
     
  • 相关阅读:
    Resize a VMWare disk (zz)
    StepbyStep: Installing SQL Server Management Studio2008 Express after Visual Studio 2010(zz)
    (C#)利用反射动态调用类成员[转载]
    Discuz!NT 系统架构分析 (转)
    C#反射实例讲解(转)
    什么是反射?
    创建保存图片目录
    取资源文件中的值 System.Resources.ResourceManager
    Net中的反射使用入门
    iis上实现虚拟目录
  • 原文地址:https://www.cnblogs.com/leonwang/p/3049112.html
Copyright © 2020-2023  润新知