jQuery源码研究分析学习笔记-回调函数(11)

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针调用它所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

// 工具函数,将字符串格式的标记转换为对象格式,并把转换结果缓存起来
function createFlags( flags ) {

    //初始化返回值object和flagsCache[flags]为空对象,同时指向了同一个空对象,当变量object添加属性时也是在为flagsCache[flags]添加属性,不需要要再写一行代码把变量object放入缓存对象flagsCache中了
    var object = flagsCache[ flags ] = {},
        i, length;
    flags = flags.split( /\s+/ ); //用空白符把标记字符串分割为数组
    //遍历数组,为返回值object添加单个标记,属性值为true,最后返回对象
    for ( i = 0, length = flags.length; i < length; i++ ) {
        object[ flags[i] ] = true;
    }
    return object;
}

jQuery.Callbacks = function( flags ) {

    // 解析字符串标记为flags为对象,先从缓存对象flagsCache中获取标记字符串flags对应的标记对象,如果没有找到,在调用工具函数createFlags(flags)将标记字符串flags解析为标记对象,并放入寒碜对象flagsCache中
    flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {};

    var // 声明局部变量,通过闭包机制引用
        list = [],//存放回调函数的数组

        //在可重复触发、正在执行的列表上,重复触发时,将上下文和参数放入数组stack中
        stack = [],

        memory,
        //
        fired,
        // 回调函数列表是否正在执行中
        firing,
        // 待执行的第一个回调函数的下标
        firingStart,
        // End of the loop when firing
        firingLength,
        // Index of currently firing callback (modified by remove if needed)
        firingIndex,
        // 添加回调函数的工具函数
        add = function( args ) {
            var i,
                length,
                elem,
                type,
                actual;
                //遍历参数args,把回调函数逐个添加到数组list中,
            for ( i = 0, length = args.length; i < length; i++ ) {
                elem = args[ i ];
                type = jQuery.type( elem );
                //判断args[i]类型,如果是数组,则迭代调用规矩函数add(args)把数组中的回调函数添加到数组list中,
                if ( type === "array" ) {

                    add( elem );
                } else if ( type === "function" ) {
                    // 如果是函数且不是unique模式,或者是unique模式但未添加过,才会添加args[i]到数组中list中
                    if ( !flags.unique || !self.has( elem ) ) {
                        list.push( elem );
                    }
                }
            }
        },
        // 触发回调函数的工具函数,使用上下文context和参数args调用数组list中的回调函数,该回调函数通过闭包机制引用数组list
        //参数context用于指定回调函数执行时的上下文,即关键字this所引用的对象,参数args用于指定调用回调函数时传入的参数
        fire = function( context, args ) {
            args = args || [];
            //若当前回调函数列表不是memory模式,则变量memory则被赋值为true,间接地表示当前回调函数列表已经被触发过
            memory = !flags.memory || [ context, args ];
            fired = true;
            firing = true;
            firingIndex = firingStart || 0;
            firingStart = 0;
            firingLength = list.length;
            for ( ; list && firingIndex < firingLength; firingIndex++ ) {
                //执行回调函数list[ firingIndex ],如果返回值是false,且当前回调函数列表是stopOnFalse模式,则变量memory被赋值为true,并停止执行后续的其他回调函数,
                if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) {
                    memory = true; // Mark as halted
                    break;
                }
            }
            firing = false;
            if ( list ) {
            //如果不是once模式,即可以多次触发回调函数列表,则从变量stack中弹出存放的下文和参数,再次执行整个回调函数列表,直到stack为空
                if ( !flags.once ) {
                    if ( stack && stack.length ) {
                        memory = stack.shift();
                        self.fireWith( memory[ 0 ], memory[ 1 ] );
                    }
                } else if ( memory === true ) {

                    self.disable();
                } else {
                    list = [];
                }
            }
        },
        // 回调函数列表,方法jQuery.Callbacks(flags)的返回值
        self = {
            // 添加回调函数
            add: function() {
                if ( list ) {
                    //先备份数组list长度
                    var length = list.length;
                    add( arguments );

                    // 如果回调函数正在执行,修正结束下标firingLength,使得新添加的回调函数也得以执行
                    if ( firing ) {
                        firingLength = list.length;

                    //
                    } else if ( memory && memory !== true ) {
                        firingStart = length;
                        fire( memory[ 0 ], memory[ 1 ] );
                    }
                }
                return this;
            },
            // 移除回调函数,从回调函数列表中移除一个或一组回调函数,移除前修正结束下标firingLength和当前下班firingIndex
            remove: function() {
                if ( list ) {
                    var args = arguments,
                        argIndex = 0,
                        argLength = args.length;
                    //遍历待移除的回调函数数组,在循环体内嵌套遍历已有的回调函数数组,
                    for ( ; argIndex < argLength ; argIndex++ ) {
                        for ( var i = 0; i < list.length; i++ ) {
                        //如果检查到某个待移除回调函数与某个已有的回调函数完全相等,则从已有的回调函数数组中移除它
                            if ( args[ argIndex ] === list[ i ] ) {
                                // 回调函数是否在列表中
                                if ( firing ) {

        //如果回调函数列表正在执行                          if ( i <= firingLength ) {
            //在移除前使用结束下标firingLength减1                          firingLength--;
            //如果待移除函数的下标小于正在执行回调函数的下标firingIndex,即待移除的回调函数已经执行,则修正firingIndex减1,以确保不会漏执行回调函数                            if ( i <= firingIndex ) {
                                            firingIndex--;
                                        }
                                    }
                                }
                                // 调用数组原型方法splice(),从匹配下标处开始移除1个元素,循环变量i自减一,修正为下一个回调函数的下标
                                list.splice( i--, 1 );
                                /
                                // 在unique模式下,数组list中不会有重复的回调函数,可以直接退出内层遍历,针对unique模式做的优化
                                if ( flags.unique ) {
                                    break;
                                }
                            }
                        }
                    }
                }
                return this;
            },
            // 回调函数是都在列表中
            has: function( fn ) {
                if ( list ) {
                    var i = 0,
                        length = list.length;
                    for ( ; i < length; i++ ) {
                        if ( fn === list[ i ] ) {
                            return true;
                        }
                    }
                }
                return false;
            },
            // 清空列表
            empty: function() {
                list = [];
                return this;
            },
            // 禁用列表
            disable: function() {
                list = stack = memory = undefined;
                return this;
            },
            // 是否已禁用列表
            disabled: function() {
                return !list;
            },
            // 锁定列表
            lock: function() {
                stack = undefined;
                if ( !memory || memory === true ) {
                    self.disable();
                }
                return this;
            },
            // 是否已错定列表
            locked: function() {
                return !stack;
            },
            // 使用指定的上下文和参数调用回调函数
            fireWith: function( context, args ) {
                if ( stack ) {
                    if ( firing ) {
                        if ( !flags.once ) {
                            stack.push( [ context, args ] );
                        }
                    } else if ( !( flags.once && memory ) ) {
                        fire( context, args );
                    }
                }
                return this;
            },
            // 使用指定的参数调用回调函数,上下文为self
            fire: function() {
                self.fireWith( this, arguments );
                return this;
            },
            // 回调函数列表是否至少执行过一次
            fired: function() {
                return !!fired;
            }
        };

    return self;
};
时间: 2024-11-02 14:54:15

jQuery源码研究分析学习笔记-回调函数(11)的相关文章

jQuery源码研究分析学习笔记-静态方法和属性(10)

jQuery源码中定义了一些重要的静态属性和方法,它们是其他模块实现的基础,整体的源码结构如下 //把window.jQuery和winow.$备份到局部变量_jQuery和_$ _jQuery = window.jQuery, // Map over the $ in case of overwrite _$ = window.$, jQuery.extend({ //许多 JavaScript 库使用 $ 作为函数或变量名,jQuery 也一样.在 jQuery 中,$ 仅仅是 jQuery

jQuery源码研究分析学习笔记-jQuery.deferred()(12)

JS是单线程语言,把每一件事情(包括GUI事件和渲染)都放在一个线程里来处理是一个很好的程序模型,因为这样就无需再考虑线程同步这些复杂问题. 但js暴露了应用开发中的一个严重问题,单线程环境看起来对用户请求响应迅速,但是当线程忙于处理其它事情时,就不能对用户的鼠标点击和键盘操作做出响应. jQuery.deferred异步模型提供了一个抽象的非阻塞的解决方案. jQuery.deferred()在jQ中常用的有: promise Ajax模块 动画模块 DOM ready jQuery.Defe

jquery源码之低调的回调函数队列--Callbacks

jQuery中有一个很实用的函数队列,可能我们很少用到,但他在jQuery内部却有着举足轻重的地位. 他就是Callbacks. jQuery作者用它构建了很多非常重要的模块.比如说$.Deferred. Callbacks 说白了就是个数组,里面存了很多函数对象.然而他真的 just so so么? 好吧,爱因斯坦也只是个人,但他真的仅仅是个普普通通的人吗?Callbacks也不是. 不说废话了,见源码. // String to Object options format cache var

jQuery源码逐行分析学习02(第一部分:jQuery的一些变量和函数)

第一次尝试使用Office Word,方便程度大大超过网页在线编辑,不过初次使用,一些内容不甚熟悉,望各位大神见谅~ 在上次的文章中,把整个jQuery的结构进行了梳理,得到了整个jQuery的简化结构,如下: 1 (function(){ 2 (21 , 94) 定义了一些变量和函数 jQuery = function(){}; 3 (96 , 283) 给JQ对象,添加一些方法和属性 4 (285 , 347) extend : JQ的继承方法 5 (349 , 817) jQuery.ex

jQuery源码逐行分析学习01(jQuery的框架结构简化)

最近在学习jQuery源码,在此,特别做一个分享,把所涉及的内容都记录下来,其中有不妥之处还望大家指出,我会及时改正.望各位大神不吝赐教!同时,这也是我的第一篇前端技术博客,对博客编写还不是很熟悉,美化工作可能不够到位,也希望大家多多见谅! 首先这篇文章要给大家分享的是:jQuery的框架结构,把框架结构简单化处理 此处我所学习使用的jQuery版本是2.0.3版本(文件已经上传到我的文件中,大家可以去下载),一个相对比较老的版本,但是其实基本的功能都与新版本类似,该版本开发版代码共8830行.

javascript arguments对象研究--针对jquery源码研究再研究

外部插件: $.fn.tinytip = function(text, customOptions) { debugger; if (text && typeof text === 'object'){ customOptions = text; text = customOptions.tooltip; } var options = $.extend({}, tooltip_options, customOptions); options.tooltip = text; if (typ

jquery源码01---(2880 , 3042) Callbacks : 回调对象 : 对函数的统一管理

// optionsCache : { 'once memory' : { once : true , memory : true } } var optionsCache = {}; // once memory,options.match( core_rnotwhite )=[once, memory],function( _, flag )={once:true,memory:true} function createOptions( options ) { var object = op

jquery源码 Callback

工具方法.对函数的统一管理. jquery2.0.3版本$.Callback()部分的源码如下: // String to Object options format cache var optionsCache = {}; // Convert String-formatted options into Object-formatted ones and store in cache function createOptions( options ) { var object = option

[转]jQuery源码分析系列

文章转自:jQuery源码分析系列-Aaron 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://github.com/JsAaron/jQuery 正在编写的书 - jQuery架构设计与实现 本人在慕课网的教程(完结) jQuery源码解析(架构与依赖模块) 64课时 jQuery源码解析(DOM与核心模块)64课时 jQuery源码分析目录(完结) jQuery源码分析系列(01) : 整体架构 jQuery源码分析系列(