快捷搜索:

jQuery回调、递延对象总结(一)jQuery.Callbacks详解

媒介:

作为参数通报给另一个函数履行的函数我们称为回调函数,那么该回调又是否是异步的呢,何谓异步,如:作为事故处置惩罚器,或作为参数通报给

(setTimeout,setInterval)这样的异步函数,或作为ajax发送哀求,利用于哀求各类状态的处置惩罚,我们可以称为异步回调,jQuery.Callbacks

为我们封装了一个回调工具模块,我们先来看一个利用处景:

// 为什么jQuery中的ready事故可以履行多个回调,这得益于我们的jQuery.Deferred递延工具(是基于jQuery.Callbacks回调模块)

jQuery(function($) {console.log('document is ready!');

// do something});

jQuery(function($) {

// do something});

// 实现原型

// jQuery.Deferred版代码var df = jQuery.Deferred();

df.resolve(); // 在ready事故中调用

// 可以多次履行绑定的函数df.done(fn1, fn2, fn3);

df.done(fn4);// ...

// jQuery.Callbacks版代码var cb = jQuery.Callbacks('once memory');

cb.fire(); // 在ready事故中调用

// 可以多次履行绑定的函数cb.add(fn1, fn2, fn3);

cb.add(fn4);// ...

现在我们知道jQuery中的ready事故是可以这样履行多个回调的,要想深入理解其源码,让我们继承看下面吧

一、jQuery.Callbacks设计思路

应用一个私有变量list(数组)存储回调,履行jQuery.Callbacks函数将返回一个可以操作回调列表list的接口工具,

而传入jQuery.Callbacks函数的options参数则用来节制返回的回调工具操作回调列表的行径

回调工具中的措施

{

add:增添回调到list中remove:从list中移除回调

fire:触发list中的回调fired:回调工具是否履行过fire措施

fireWith:触发list中的回调,第一个参数为履行域has:判断函数是否在list中

empty:将list致空,list = [];lock:锁定list

locked:是否锁定disable:禁用回调工具

disabled:是否禁用}

参数标志:

options = {

once:回调工具仅触发(fire)一次

memory:跟踪记录每一次通报给fire函数的参数,在回调工具触发后(fired),将着末一次触发(fire)时的参数(value)通报给在add操作后即将被调用的回调

unique:在add操作中,相同的函数仅只一次被添加(push)到回调列表中

stopOnFalse:当回调函数返回false,中断列表中的回调轮回调用,且memory === false,阻拦在add操作中将要触发的回调

}

二、源码解析

var // Used for splitting on whitespace

core_rnotwhite = /\S+/g;

var optionsCache = {};

// Convert String-formatted options into Object-formatted ones and store in cache// 将字符串款式选项转化成工具款式形式,并存储在缓存工具optionsCache[options]中

// 该缓存起感化适用于履行多次jQuery.Callbacks函数,且通报options参数同等,我们在jQuery.Deferred// 源码就可以看到tuples二维数组中履行了两次jQuery.Callbacks('once memory')

function createOptions( options ) {var object = optionsCache[ options ] = {};

jQuery.each( options.match( core_rnotwhite ) || [], function( _, flag ) {object[ flag ] = true;

});return object;

}jQuery.Callbacks = function( options ) {

// Convert options from String-formatted to Object-formatted if needed

// (we check in cache first)options = typeof options === "string" ?

( optionsCache[ options ] || createOptions( options ) ) :jQuery.extend( {}, options );

var // Flag to know if list is currently firing

firing,// Last fire value (for non-forgettable lists)

memory,// Flag to know if list was already fired

fired,// End of the loop when firing

firingLength,// Index of currently firing callback (modified by remove if needed)

firingIndex,// First callback to fire (used internally by add and fireWith)

firingStart,// Actual callback list

list = [],// Stack of fire calls for repeatable lists

stack = !options.once && [],// Fire callbacks

fire = function( data ) {memory = options.memory && data;

fired = true;firingIndex = firingStart || 0;

firingStart = 0;firingLength = list.length;

firing = true;// 迭代list回调列表,列表中的回调被利用(或履行回调)

for ( ; list && firingIndex// 假如回调返回false,且options.stopOnFlase === true,则中断轮回

// 注:data[1]是一个伪数组(self.fire措施中的arguments(参数聚拢))if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {

memory = false; // To prevent further calls using add// 阻拦在add操作中可能履行的回调break;

}}

firing = false;if ( list ) {

// (options.once === undefined),回调工具可以触发多次if ( stack ) {

// 处置惩罚正在履行的回调中的fireWith操作// 注:假如履行的回调中真的拥有fire或fireWith操作,那么列表中的回调将会无限轮回的履行,请看实例1

if ( stack.length ) {fire( stack.shift() );

}}

// (options.once === true && options.memory === true)// 回调列表致空,但容许add继承添加并履行回调

else if ( memory ) {list = [];

}// (options.once === true && options.memory === undefined)

// 禁用回调工具else {

self.disable();}

}},

// Actual Callbacks objectself = {

// Add a callback or a collection of callbacks to the listadd: function() {

if ( list ) {// First, we save the current length

var start = list.length;(function add( args ) {

jQuery.each( args, function( _, arg ) {var type = jQuery.type( arg );

if ( type === "function" ) {// 回调不独一 或 独一且不存在,则push

if ( !options.unique || !self.has( arg ) ) {list.push( arg );

}} else if ( arg && arg.length && type !== "string" ) {

// Inspect recursively// 递归反省

add( arg );}

});})( arguments );

// Do we need to add the callbacks to the

// current firing batch?// 假如正在履行的回调履行了add操作,更新firingLength,将列表中新加进来的着末一个回调加入到回调履行的行列步队中

if ( firing ) {firingLength = list.length;

// With memory, if we're not firing then

// we should call right away// 假如可能(options.memory === true),在回调工具不能再次fire(options.once === true)时,

// 我们应该应用memory(记录的着末一次fire时的参数)急速调用回调} else if ( memory ) {

firingStart = start;fire( memory );

}}

return this;},

// Remove a callback from the listremove: function() {

if ( list ) {jQuery.each( arguments, function( _, arg ) {

var index;while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {

list.splice( index, 1 );// Handle firing indexes

// 在回调工具触发(fire)时,假如firingLength、firingIndex(正在履行的回调在列表list中的索引index)// 大年夜于即是 移除的回调的索引(index),分手减一,确保回调履行行列步队中未履行的回调依次履行

if ( firing ) {if ( index

firingLength--;}

if ( indexfiringIndex--;

}}

}});

}return this;

},// Check if a given callback is in the list.

// If no argument is given, return whether or not list has callbacks attached.// 反省给定的回调是否在列表中

// 假如未给定回调参数,返回列表是否有回调has: function( fn ) {

return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );},

// Remove all callbacks from the list// 将列表致空,list = []; firingLenght = 0;

empty: function() {list = [];

firingLength = 0;return this;

},// Have the list do nothing anymore

// 禁用回调工具// 将list赋值为undefined就可以使self中的add,remove,fire,fireWith措施竣事事情

// 我觉得这里把stack、memory赋值为undefined与否是没有任何关系的disable: function() {

list = stack = memory = undefined;return this;

},// Is it disabled?

disabled: function() {return !list;

},// Lock the list in its current state

// 锁定回调列表// 假如(fired !== true || options.memory === false),则视为禁用(disable)

// 假如(fired === true && options.memory === true),则视为options.once === true// 请看实例2

lock: function() {stack = undefined;

if ( !memory ) {self.disable();

}return this;

},// Is it locked?

locked: function() {return !stack;

},// Call all callbacks with the given context and arguments

fireWith: function( context, args ) {// 回调工具未履行过fire 或且 可以履行多次(options.once === false)

// 假如(fired === true && options.once === true),则不会履行fire操作if ( list && ( !fired || stack ) ) {

args = args || [];args = [ context, args.slice ? args.slice() : args ];

if ( firing ) {stack.push( args );

} else {fire( args );

}}

return this;},

// Call all the callbacks with the given argumentsfire: function() {

self.fireWith( this, arguments );return this;

},// To know if the callbacks have already been called at least once

fired: function() {return !!fired;

}};

return self;

};

三、实例

实例1、 处置惩罚回调函数中的fire,或fireWidth操作

var cb = jQuery.Callbacks();

var fn1 = function(arg){ console.log( arg + '1' ); };

var fn2 = function(arg){ console.log( arg + '2' ); cb.fire();};var fn3 = function(arg){ console.log( arg + '3' ); };

cb.add(fn1, fn2, fn3);

cb.fire('fn'); // 此中回调fn1,fn2,fn3无限定的轮回调用

/*

节制台将无限定输出如下:fn1

fn2fn3

fn1fn2

fn3fn1

fn2fn3

..

.*/

实例2、 锁定(lock)操作各类场景中的用法

var cb1 = jQuery.Callbacks();

var cb2 = jQuery.Callbacks('memory');var cb3 = jQuery.Callbacks('memory');

var fn1 = function(arg){ console.log( arg + '1' ); };

var fn2 = function(arg){ console.log( arg + '2' ); };var fn3 = function(arg){ console.log( arg + '3' ); };

// 假如options.memory !== true,锁定操作视为禁用回调工具

cb1.add(fn1);cb1.lock();

// 以下操作无任何反映cb1.add(fn2);

cb1.fire('fn');

// 假如fried !== true,锁定操作也视为禁用回调工具cb2.add(fn1);

cb2.lock();// 以下操作无任何反映

cb2.add(fn2);cb2.fire('fn');

// 假如(fired === true && options.memory === true),锁定操作类似节制标志once(options.once === true);

cb3.add(fn1);cb3.fire('fn'); // fn1,此时fired === true

cb3.lock();// 像是传入了'once'标志,jQuery.Callbacks('once memory');cb3.add(fn2);// fn2

cb3.fire('fn'); // 再次触发,无任何反映cb3.add(fn3);// fn3

// 再来看看jQuery.Deferred中的一段源码var tuples = [

// action, add listener, listener list, final state[ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],

[ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],[ "notify", "progress", jQuery.Callbacks("memory") ]

];

// Handle stateif ( stateString ) {

list.add(function() {// state = [ resolved | rejected ]

state = stateString;

// [ reject_list | resolve_list ].disable; progress_list.lock}, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );

}

/*当履行了tuples中前面两组中随意率性一个回调工具的fire措施时,后一组回调工具被锁定,

相称于(fired === true && options.memory === true),后一组回调工具实际为履行jQuery.Callbacks('once memory')天生的回调工具。

*/

转自:http://www.cnblogs.com/yangjunhua/p/3508502.html

您可能还会对下面的文章感兴趣: