最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
当前位置: 首页 - 科技 - 知识百科 - 正文

jQuery源码之Callbacks的学习

来源:懂视网 责编:小采 时间:2020-11-27 19:34:01
文档

jQuery源码之Callbacks的学习

jQuery源码之Callbacks的学习:这篇文章主要介绍了关于jQuery源码之Callbacks的学习,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下jQuery源码学习之CallbacksjQuery的ajax、deferred通过回调实现异步,其实现核心是Callbacks。使用方法使用首先要先新建一个实例对
推荐度:
导读jQuery源码之Callbacks的学习:这篇文章主要介绍了关于jQuery源码之Callbacks的学习,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下jQuery源码学习之CallbacksjQuery的ajax、deferred通过回调实现异步,其实现核心是Callbacks。使用方法使用首先要先新建一个实例对

这篇文章主要介绍了关于jQuery源码之Callbacks的学习,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下

jQuery源码学习之Callbacks

jQuery的ajaxdeferred通过回调实现异步,其实现核心是Callbacks

使用方法

使用首先要先新建一个实例对象。创建时可以传入参数flags,表示对回调对象的限制,可选值如下表示。

  • stopOnFalse:回调函数队列中的函数返回false时停止触发

  • once:回调函数队列只能被触发一次

  • memory:记录上一次触发队列传入的值,新添加到队列中的函数使用记录值作为参数,并立即执行。

  • unique:函数队列中函数都是唯一的

  • var cb = $.Callbacks('memory');
    cb.add(function(val){
     console.log('1: ' + val)
    })
    cb.fire('callback')
    cb.add(function(val){
     console.log('2: ' + val)
    })
    // console
    输出 1: callback 2: callback

    Callbacks 提供了一系列实例方法来操作队列和查看回调对象的状态。

  • add: 添加函数到回调队列中,可以是函数或者函数数组

  • remove: 从回调队列中删除指定函数

  • has: 判断回调队列里是否存在某个函数

  • empty: 清空回调队列

  • disable: 禁止添加函数和触发队列,清空回调队列和上一个传入的值

  • disabled: 判断回调对象是否被禁用

  • lock: 禁用fire,若memory非空则同时add无效

  • locked: 判断是否调用了lock

  • fireWith: 传入context和参数,触发队列

  • fire: 传入参数触发对象,context是回调对象

  • 源码解析

    $.Callback()方法内部定义了多个局部变量和方法,用于记录回调对象的状态和函数队列等,返回self,在self实现了上述回调对象的方法,用户只能通过self提供的方法来更改回调对象。这样的好处是保证除了self之外,没有其他修改回调对象的状态和队列的途径。

    其中,firingIndex为当前触发函数在队列中的索引,list是回调函数队列,memory记录上次触发的参数,当回调对象实例化时传入memory时会用到,queue保存各个callback执行时的context和传入的参数。self.fire(args)实际是self.fireWith(this,args)self.fireWith内部则调用了在Callbacks定义的局部函数fire

     ...
     // 以下变量和函数 外部无法修改,只能通过self暴露的方法去修改和访问
     var // Flag to know if list is currently firing
     firing,
    
     // Last fire value for non-forgettable lists
     // 保存上一次触发callback的参数,调用add之后并用该参数触发
     memory,
    
     // Flag to know if list was already fired
     fired,
    
     // Flag to prevent firing
     // locked==true fire无效 若memory非空则同时add无效
     locked,
    
     // Actual callback list
     // callback函数数组
     list = [],
    
     // Queue of execution data for repeatable lists
     // 保存各个callback执行时的context和传入的参数
     queue = [],
    
     // Index of currently firing callback (modified by add/remove as needed)
     // 当前正触发callback的索引
     firingIndex = -1,
    
     // Fire callbacks
     fire = function() {
     ...
     },
     
     // Actual Callbacks object
     self = {
     // Add a callback or a collection of callbacks to the list
     add: function() {
     ...
     },
     ...
     // Call all callbacks with the given context and arguments
     fireWith: function( context, args ) {
     if ( !locked ) {
     args = args || [];
     args = [ context, args.slice ? args.slice() : args ]; // :前为args是数组,:后是string
     queue.push( args );
     if ( !firing ) {
     fire();
     }
     }
     return this;
     },
    
     // Call all the callbacks with the given arguments
     fire: function() {
     self.fireWith( this, arguments );
     return this;
     },
     ...
     }

    通过self.add添加函数到回调队列中,代码如下。先判断是否memory且非正在触发,如果是则将fireIndex移动至回调队列的末尾,并保存memory。接着使用立即执行函数表达式实现add函数,在该函数内遍历传入的参数,进行类型判断后决定是否添加到队列中,如果回调对象有unique标志,则还要判断该函数在队列中是否已存在。如果回调对象有memory标志,添加完毕之后还会触发fire,执行新添加的函数。

     add: function() {
     if ( list ) {
    
     // If we have memory from a past run, we should fire after adding
     // 如果memory非空且非正在触发,在queue中保存memory的值,说明add后要执行fire
     // 将firingIndex移至list末尾 下一次fire从新add进来的函数开始
     if ( memory && !firing ) {
     firingIndex = list.length - 1;
     queue.push( memory );
     }
    
     ( function add( args ) {
     jQuery.each( args, function( _, arg ) {
     // 传参方式为add(fn)或add(fn1,fn2)
     if ( jQuery.isFunction( arg ) ) {
     /**
     * options.unique==false
     * 或
     * options.unique==true&&self中没有arg
     */
     if ( !options.unique || !self.has( arg ) ) {
     list.push( arg );
     }
     } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) {
     // 传参方式为add([fn...]) 递归
     // Inspect recursively
     add( arg );
     }
     } );
     } )( arguments ); //arguments为参数数组 所以add的第一步是each遍历
    
     //添加到list后若memory真则fire,此时firingIndex为回调队列的最后一个函数
     if ( memory && !firing ) {
     fire();
     }
     }
     return this;
     }

    firefireWith方法内部实际调用了局部函数fire,其代码如下。触发时,需要更新firedfiring,表示已触发和正在触发。通过for循环执行队里中的函数。结束循环后,将firingIndex更新为-1,表示下次触发从队列中的第一个函数开始。遍历在fireWith中更新过的queuequeue是保存数组的数组,每个数组的第一个元素是context,第二个元素是参数数组。执行函数时要是否返回false且回调对象有stopOnFalse标志,如果是则停止触发。

    // Fire callbacks
     fire = function() {
    
     // Enforce single-firing
     // 执行单次触发
     locked = locked || options.once;
    
     // Execute callbacks for all pending executions,
     // respecting firingIndex overrides and runtime changes
     // 标记已触发和正在触发
     fired = firing = true;
     // 循环调用list中的回调函数
     // 循环结束之后 firingIndex赋-1 下一次fire从list的第一个开始 除非firingIndex被修改过
     // 若设置了memory,add的时候会修改firingIndex并调用fire
     // queue在fireWith函数内被更新,保存了触发函数的context和参数
     for ( ; queue.length; firingIndex = -1 ) {
     memory = queue.shift();
     while ( ++firingIndex < list.length ) { 
    
     // Run callback and check for early termination
     // memory[0]是content memory[1]是参数
     if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&
     options.stopOnFalse ) {
     
     // Jump to end and forget the data so .add doesn't re-fire
     // 当前执行函数范围false且options.stopOnFalse==true 直接跳至list尾 终止循环
     firingIndex = list.length;
     memory = false;
     }
     }
     }
    
     // 没设置memory时不保留参数
     // 设置了memory时 参数仍保留在其中
     // Forget the data if we're done with it
     if ( !options.memory ) {
     memory = false;
     }
    
     firing = false;
    
     // Clean up if we're done firing for good
     if ( locked ) {
    
     // Keep an empty list if we have data for future add calls
     if ( memory ) {
     list = [];
    
     // Otherwise, this object is spent
     } else {
     list = "";
     }
     }
     },

    文档

    jQuery源码之Callbacks的学习

    jQuery源码之Callbacks的学习:这篇文章主要介绍了关于jQuery源码之Callbacks的学习,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下jQuery源码学习之CallbacksjQuery的ajax、deferred通过回调实现异步,其实现核心是Callbacks。使用方法使用首先要先新建一个实例对
    推荐度:
    标签: 的学习 源码 jQuery
    • 热门焦点

    最新推荐

    猜你喜欢

    热门推荐

    专题
    Top