`
aijuans
  • 浏览: 1547097 次
社区版块
存档分类
最新评论

jQuery Callbacks

 
阅读更多

jQuery.Callbacks是jQuery的多用途核心组件,专职负责回调函数列队管理,其在jQuery的$.ajax() 和 $.Deferred()提供了一些基础功能。

其主要提供了易于管理的批量回调函数处理的功能。

说到批处理,在Javascript库中屡见不鲜:

等等…………

为了理解Callbacks函数的实现,我们先来了解下jQuery.each()。

 

each()

我们可以在jQuery的源文件core.js找到其完整实现:

/*********************
 *    obj: 队列列表
 *    callback: 回调函数
 *    args: 回调函数的参数
 */
jQuery.each = function( obj, callback, args ) {
    var value,
        i = 0,
        length = obj.length,
        isArray = isArraylike( obj );    //obj是否是类Array对象

    //如果有参数
    if ( args ) {
        //如果obj是类Array对象
        if ( isArray ) {
            for ( ; i < length; i++ ) {
                value = callback.apply( obj[ i ], args );
                if ( value === false ) {
                    break;
                }
            }
        //否则
        } else {
            for ( i in obj ) {
                value = callback.apply( obj[ i ], args );
                if ( value === false ) {
                    break;
                }
            }
        }
    //如果没有参数,则是一个更为常用的each函数
    } else {
        if ( isArray ) {
            for ( ; i < length; i++ ) {
                value = callback.call( obj[ i ], i, obj[ i ] );
                if ( value === false ) {
                    break;
                }
            }
        } else {
            for ( i in obj ) {
                value = callback.call( obj[ i ], i, obj[ i ] );
                if ( value === false ) {
                    break;
                }
            }
        }
    }

    return obj;
}

借助这个函数我们jQuery实现了其他each函数。如:

$( "li" ).each(function( index ) {
  console.log( index + ": "" + $(this).text() );
});

这里的each实际上只是一个没有args回调函数参数的jQuery.each。

 

简易Callbacks

实际上对简单的回调函数进行变形,我们也能弄成类似回调函数队列的效果:

function dosomething(__callbacks){
    //do something......
    for(var i = __callbacks.length; i--;){
        __callbacks[i]();
    }
}

但jQuery.CallBacks可以为我们提供更丰富的功能,和更方便的管理方法。

 

jQuery.Callbacks(flags)

flags:一个用空格标记分隔的标志可选列表,用来改变回调列表中的行为

  • once: 确保这个回调列表只执行一次(像一个递延 Deferred).
  • memory: 保持以前的值和将添加到这个列表的后面的最新的值立即执行调用任何回调 (像一个递延 Deferred).
  • unique: 确保一次只能添加一个回调(所以有没有在列表中的重复).
  • stopOnFalse: 当一个回调返回false 时中断调用
  • callbacks.add(callbacks)

回调列表中添加一个回调或回调的集合。

callbacks:一个函数,或者一个函数数组用来添加到回调列表。

  • callbacks.remove(callbacks)

删除回调或回调回调列表的集合。

callbacks:一个函数或函数数组,是从回调列表中删除。 

  • callbacks.fire(arguments)

调用所有回调函数,并将arguments传给他们。

arguments:这个参数或参数列表传回给回调列表。

  • callbacks.disable()

禁用回调列表中的回调。

例子:

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 ); //重复添加
callbacks.add( fn2 );
callbacks.fire( "bar" );
callbacks.add( fn2 );
callbacks.fire( "baz" );
callbacks.remove( fn2 );
callbacks.fire( "foobar" );

/*
output:
foo
fn2 says:foo
bar
fn2 says:bar
baz
fn2 says:baz
foobar
*/

 

optionsCache

我们看到上面的例子中,flags参数是以字符串形式,每个参数以空格间隔,如:

$.Callbacks( "unique memory" );

大家会如何将字符串转成参数呢?

在这里Callbacks会通过正则表达式将字符串转数组,然后再组装成参数对象,如上面的例子,则最后参数对象是:

{
    unique: true,
    memory: true
}

再将这个对象缓存到optionsCache,以便下次使用。

//参数对象缓存
var optionsCache = {};

//将字符串表达转成对象表达,并存在缓存中
function createOptions( options ) {
    var object = optionsCache[ options ] = {};
    jQuery.each( options.match( core_rnotwhite ) || [], function( _, flag ) {
        object[ flag ] = true;
    });
    return object;
}

jQuery.Callbacks = function( options ) {
    
    //通过字符串在optionsCache寻找有没有相应缓存,如果没有则创建一个,有则引用
    //如果是对象则通过jQuery.extend深复制后赋给options。
    options = typeof options === "string" ?
        ( optionsCache[ options ] || createOptions( options ) ) :
        jQuery.extend( {}, options );

    //………………
    
}

其他地方的实现比较像一个单一事件的自定义事件处理对象,通过add添加事件处理函数,用remove删除事件处理函数,用fire触发事件。

有兴趣请参照下面的完整备注。 

 

完整备注

jQuery.Callbacks = function( options ) {

    //通过字符串在optionsCache寻找有没有相应缓存,如果没有则创建一个,有则引用
    //如果是对象则通过jQuery.extend深复制后赋给options。
    options = typeof options === "string" ?
        ( optionsCache[ options ] || createOptions( options ) ) :
        jQuery.extend( {}, options );

    var // 最后一次触发回调时传的参数
        memory,
        // 列表中的函数是否已经回调至少一次
        fired,
        // 列表中的函数是否正在回调中
        firing,
        // 回调的起点
        firingStart,
        // 回调时的循环结尾
        firingLength,
        // 当前正在回调的函数索引
        firingIndex,
        // 回调函数列表
        list = [],
        // 可重复的回调函数堆栈,用于控制触发回调时的参数列表
        stack = !options.once && [],
        // 触发回调函数列表
        fire = function( data ) {
            //如果参数memory为true,则记录data
            memory = options.memory && data;
            //标记触发回调
            fired = true;
            firingIndex = firingStart || 0;
            firingStart = 0;
            firingLength = list.length;
            //标记正在触发回调
            firing = true;
            for ( ; list && firingIndex < firingLength; firingIndex++ ) {
                if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
                    memory = false; // 阻止未来可能由于add所产生的回调
                    break;    //由于参数stopOnFalse为true,所以当有回调函数返回值为false时退出循环
                }
            }
            //标记回调结束
            firing = false;
            //如果列表存在
            if ( list ) {
                //如果堆栈存在
                if ( stack ) {
                    //如果堆栈不为空
                    if ( stack.length ) {
                        //从堆栈头部取出,递归fire。
                        fire( stack.shift() );
                    }
                //否则,如果有记忆
                } else if ( memory ) {
                    //列表清空
                    list = [];
                //再否则阻止回调列表中的回调
                } else {
                    self.disable();
                }
            }
        },
        // 暴露在外的Callbacks对象
        self = {
            // 回调列表中添加一个回调或回调的集合。
            add: function() {
                if ( list ) {
                    // 首先我们存储当前列表长度
                    var start = list.length;
                    (function add( args ) {
                        //前面我们看到的jQuery.each,对args传进来的列表的每一个对象执行操作
                        jQuery.each( args, function( _, arg ) {
                            //得到arg的类型
                            var type = jQuery.type( arg );
                            //如果是函数
                            if ( type === "function" ) {
                                //确保是否可以重复
                                if ( !options.unique || !self.has( arg ) ) {
                                    list.push( arg );
                                }
                            //如果是类数组或对象
                            } else if ( arg && arg.length && type !== "string" ) {
                                //递归
                                add( arg );
                            }
                        });
                    })( arguments );
                    // 如果正在回调就将回调时的循环结尾变成现有长度
                    if ( firing ) {
                        firingLength = list.length;
                    // 如果有memory,我们立刻调用。
                    } else if ( memory ) {
                        firingStart = start;
                        fire( memory );
                    }
                }
                return this;
            },
            // 从列表删除回调函数
            remove: function() {
                if ( list ) {
                    //继续用jQuery.each,对arguments中的所有参数处理
                    jQuery.each( arguments, function( _, arg ) {
                        var index;
                        //找到arg在列表中的位置
                        while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
                            //根据得到的位置删除列表中的回调函数
                            list.splice( index, 1 );
                            //如果正在回调过程中,则调整循环的索引和长度
                            if ( firing ) {
                                if ( index <= firingLength ) {
                                    firingLength--;
                                }
                                if ( index <= firingIndex ) {
                                    firingIndex--;
                                }
                            }
                        }
                    });
                }
                return this;
            },
            // 回调函数是否在列表中
            has: function( fn ) {
                return jQuery.inArray( fn, list ) > -1;
            },
            // 从列表中删除所有回调函数
            empty: function() {
                list = [];
                return this;
            },
            // 禁用回调列表中的回调。
            disable: function() {
                list = stack = memory = undefined;
                return this;
            },
            // 列表中否被禁用
            disabled: function() {
                return !list;
            },
            // 锁定列表
            lock: function() {
                stack = undefined;
                if ( !memory ) {
                    self.disable();
                }
                return this;
            },
            // 列表是否被锁
            locked: function() {
                return !stack;
            },
            // 以给定的上下文和参数调用所有回调函数
            fireWith: function( context, args ) {
                args = args || [];
                args = [ context, args.slice ? args.slice() : args ];
                if ( list && ( !fired || stack ) ) {
                    //如果正在回调
                    if ( firing ) {
                        //将参数推入堆栈,等待当前回调结束再调用
                        stack.push( args );
                    //否则直接调用
                    } else {
                        fire( args );
                    }
                }
                return this;
            },
            // 以给定的参数调用所有回调函数
            fire: function() {
                self.fireWith( this, arguments );
                return this;
            },
            // 回调函数列表是否至少被调用一次
            fired: function() {
                return !!fired;
            }
        };

    return self;
};
分享到:
评论

相关推荐

    jQuery Callback 方法

    jQuery Callback 方法 Callback 函数在当前动画 100% 完成之后执行。 jQuery 动画的问题 许多 jQuery 函数涉及动画。这些函数也许会将 speed 或 duration 作为可选参数。 例子:$(“p”).hide(“slow”) speed 或 ...

    爬虫爬到的内容_JS生成的数据基于JQuery

    爬到的内容,用处不大,爬虫爬到的内容_JS生成的数据基于JQuery

    jQuery详细教程

    jQuery详细教程,讲解很透彻, 一. jQuery 语法实例 $(this).hide() 演示 jQuery hide() 函数,隐藏当前的 HTML 元素。 $("#test").hide() 演示 jQuery hide() 函数,隐藏 id="test" 的元素。 $("p").hide() ...

    jQuery的帮助文档

    jQuery特效、jQuery语法、jQuery切换、jQuery滑动函数、jQuery自定义动画、jQuery Callback函数 等等

    锋利的jquery:jquery学习资料和中文参考文档

    学习资料包括: 1.JQuery简介 2.JQuery语法 3.JQuery选择器 4.JQuery事件 ...5.JQuery Callback函数 6.JQuery常用函数 另外还有jquery中文参考文档,希望能对想要学习jquery的朋友有所帮助!

    jQuery事件回调李斯特「jQuery Event Callback Lister」-crx插件

    用于查看jQuery回调事件的...此插件在“元素”面板上添加了一个新的侧边栏-jQuery Callback Events侧边栏-显示了所选元素的事件处理程序,包括正在发生或委托给对所选元素有影响的其他元素的事件。 支持语言:English

    在线培训:JQuery

    本次在线培训任务 JQuery简介 JQuery语法 JQuery选择器 JQuery事件 JQuery Callback函数 JQuery常用函数 JQuery实现图片预览效果

    jQuery使用文档.doc

    • jQuery 教程 • jQuery 简介 • jQuery 语法 • jQuery 选择器 • jQuery 事件 • jQuery 效果 • jQuery Callback • jQuery HTML • jQuery CSS • jQuery AJAX • jQuery 实例

    JQuery语法

    详细讲解JQuery语法,JQuery选择器,JQuery事件,JQuery效果,JQuery Callback函数,JQuery HTML操作,JQuery CSS函数,JQuery Ajax函数的使用。

    jQuery Event Callback Lister-crx插件

    语言:English Chrome开发人员工具扩展程序,...此插件在“元素”面板上添加了一个新的侧边栏-jQuery Callback Events侧边栏-显示了所选元素的事件处理程序,包括正在发生或委托给对所选元素有影响的其他元素的事件。

    jquery get id val from callback

    NULL 博文链接:https://jeemygrow.iteye.com/blog/1271174

    jQuery 1.4.1 中文参考

    2.1.6 jQuery(callback) 21 2.2 jQuery 对象访问 22 2.2.1 each(callback) 22 2.2.2 size() 23 2.2.3 length 24 2.2.4 selector 24 2.2.5 context 25 2.2.6 get() 25 2.2.7 get(index) 25 2.2.8 index([subject]) 26...

    jQuery中文API

    jquery中文文档api, jQuery 核心函数 jQuery([sel,[context]]) jQuery(html,[ownerDoc]) jQuery(callback) jQuery.holdReady(hold)1.6+ jQuery 对象访问 each(callback) size() length selector context get([index]...

    jQuery 参考手册 速查表

    jQuery(callback) jQuery.holdReady(hold) jQuery 对象访问 each(callback) size() length selector context get([index]) index([selector|element]) 数据缓存 data([key],[value]) removeData([name|...

    react.js essentials

    Are you tired of writing jQuery callback soup? Does your blood boil when you need to write yet another template or configuration in your Angular app? Wondering why your application structure is so ...

    演示如何实现jquery的回调函数

    通过jquery,通过ajax技术访问 server.asp,然后在用回调函数实现本地javascript的调用。这样可以实现通过服务器端控制客户端的html元素。 &lt;!--html客户端代码,演示如何调用jquery的回调函数--&gt;

    jQuery 回调函数(callback)的使用和基础

    主要介绍了jQuery 回调函数(callback)的使用和基础,需要的朋友可以参考下

    jquery中文版手册(超级实用)

    jquery的使用手册,中文版 jQuery 核心函数 ...jQuery(callback) jQuery.holdReady(hold)1.6+ jQuery 对象访问 each(callback) size() length selector context get([index]) index([selector|element])

    jquery.i18n.properties和jquery.easyui.min

    callback : function() {//加载成功后设置显示内容 //以下是将要国际化的文字内容 //退出 $("#logOut").html($.i18n.prop('logOut')); //用户 $("#loginUser").html($.i18n.prop('loginUser')) } });...

Global site tag (gtag.js) - Google Analytics