这篇文章主要介绍了关于jquery源码之callbacks的学习,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下
jquery源码学习之callbacksjquery的ajax、deferred通过回调实现异步,其实现核心是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: callback2: 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; }
fire、firewith方法内部实际调用了局部函数fire,其代码如下。触发时,需要更新fired和firing,表示已触发和正在触发。通过for循环执行队里中的函数。结束循环后,将firingindex更新为-1,表示下次触发从队列中的第一个函数开始。遍历在firewith中更新过的queue,queue是保存数组的数组,每个数组的第一个元素是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 = ""; } } },
以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注!
相关推荐:
js 异步for循环的介绍
jquery-ajax请求json数据并加载在前端页面
以上就是jquery源码之callbacks的学习的详细内容。