回调列表
jQuery的应用
在jQuery1.5之前 ajax的api如下
$.ajax({
url: '',
success:function(data, status, xhr){...},
error:function(xhr, status, errMsg){...},
complete:function(xhr, status){...}
})
而在1.5之后加入了队列
$.ajax(url)
.done:function(data, textStatus, jqXHR){...} //对应success
.done:function(data, textStatus, jqXHR){...}
.fail: function(jqXHR, textStatus, errorThrown){...}
.fail: function(jqXHR, textStatus, errorThrown){...}
.complete:function(jqXHR, statusText){...}
.complete:function(jqXHR, statusText){...}
})
简单来说就是可以定义多个成功/失败的事件,然后按顺序执行
Callbacks函数
jQuery.Callbacks( options )
options可以多选的四个值
- once: 回调列表只能被fire一次
- memory: 记得上次触发回调函数列表的参数,之后添加任何回调函数都将用记录的参数值立即回调
- 确认一个回调函数智能被添加一次
- 当某个回调函数返回false终端执行
可以在https://api.jquery.com/jQuery.Callbacks/
里查看更多demo方便理解
DEMO
说实话,使用和理解之前需要好好研究一下他用法
辅助型输出
function fn1( value ) {
console.log( "fn1 says: " + value );
return false; //为了演示stopOnFalse,不影响其他属性
}
function fn2( value ) {
console.log( "fn2 says: " + value );
}
没参数的情况
var callbacks = $.Callbacks();
callbacks.add( fn1 );
callbacks.fire( "foo!" );// fn1 says: foo!
callbacks.add( fn2 );
callbacks.fire( "bar!" );// fn1 says: bar! fn2 says: bar!
callbacks.remove( fn2 );
callbacks.fire( "foobar" ); //fn1 says: foobar
once
var callbacks = $.Callbacks( "once" );
callbacks.add( fn1 );
callbacks.fire( "foo" ); //fn1 says: foo
callbacks.add( fn2 );
callbacks.fire( "bar" );
callbacks.remove( fn2 );
callbacks.fire( "foobar" );
memory
var callbacks = $.Callbacks( "memory" );
callbacks.add( fn1 );
callbacks.fire( "foo" ); //fn1 says: foo
callbacks.add( fn2 ); //fn2 says: foo
callbacks.fire( "bar" ); //fn1 says: bar fn2 says: bar
callbacks.remove( fn2 );
callbacks.fire( "foobar" );//fn1 says: foobar
unique
var callbacks = $.Callbacks( "unique" );
callbacks.add( fn1 );
callbacks.fire( "foo" ); //fn1 says: foo
callbacks.add( fn1 ); // Repeat addition
callbacks.add( fn2 );
callbacks.fire( "bar" ); //fn1 says: bar fn2 says: bar
callbacks.remove( fn2 );
callbacks.fire( "foobar" ); //fn1 says: foobar
stopOnFalse
var callbacks = $.Callbacks( "stopOnFalse" );
callbacks.add( fn1 );
callbacks.fire( "foo" ); //fn1 says: foo
callbacks.add( fn2 );
callbacks.fire( "bar" ); //fn1 says: bar
callbacks.remove( fn2 );
callbacks.fire( "foobar" );//fn1 says: foobar
API
- add(callbacks)
- remove(callbacks)
- has(callback) //判断函数是否在回调列表中
- empty() /清空回调队列
结构
jQuery.Callbacks = function( options ) {
firing, //是否正在执行回调函数
memory, //最后一个被fire时的参数,从queue属性了shift()出来的
fired, //是否正在fired
locked,//改函数队列是否已经锁定,不被执行 手动lock()和once时fire一次时为true
list = [], //真实的回调队列,里面存储着用户add进来的函数
queue = [], //存储着fire时的参数,queue里面也是数组[0: context,1: 具体fire时的参数]
firingIndex = -1, //记录当前队列正在执行第几个回调函数
fire(),
self = {
add(callbacks),//添加一个或一组回调函数
remove(), //删除一个或一组回调函数
has( [fn] ), //当fn为空时,判断是否有回调列表,不为空时,判断fn是否在回调列表中
empty(), //清空list(真实回调队列)
disable(),//disable掉.add()和.fire(),真正的disable,因为当memory模式时,add也会触发.fire()
disabled(),//是否disable
lock(),//锁定队列,disable掉.fire()
locked(),//判断是否回调队列已经被锁定
fireWith( context, args ), //触发回调队列
fire(args),//触发回调队列
fired(), //是否正在触发
}
}
重点
memory模式下记录参数
只会记住上一次fire的参数
var callbacks = $.Callbacks( "memory" );
callbacks.add( fn1 );
callbacks.fire( "foo" ); //fn1 says: foo
callbacks.fire( "foo2" ); //fn1 says: foo2
callbacks.add( fn2 ); //fn2 says: foo2
通过queue记录最后一个fire的参数
以下代码被我修饰过,去掉了和memory无关的代码
var memory, //记录最后一个fire的参数
queue = [], //存储当时fire时的参数
list = [],//存储真实add进来的行数
fire = function() { //内部fire函数
...
for ( ; queue.length ; firingIndex = -1) {
memory = queue.shift()
while( ++firingIndex < list.length) {
list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ]
}
}
...
},
self = {
add: function (){
if ( memory && !firing ) {
firingIndex = list.length - 1;
queue.push( memory );
}
( function add( args ) { //属性内定义方法比较优秀的写法
jQuery.each( args, function( _, arg ) {
if ( jQuery.isFunction( arg ) ) {
if ( !options.unique || !self.has( arg ) ) { //如果是unique的防重复
list.push( arg );
}
} else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) {
// Inspect recursively 递归检查
add( arg );
}
} );
} )( arguments );
if ( memory && !firing ) {
fire();
}
},
fireWith: function( context, args ) { //调用.fire()实际调用的方法
var args = [ context, args ]
queue.push (args)
fire()//内部的fire函数
}
}