jQuery.Callbacks(flags)
一个多用途的回调函数列表对象,提供一种强大的方式来管理回调函数列表。
-
1.7 新增jQuery.Callbacks(flags)
flags (String) 一个可选的列表标记字符串,字符串之间使用空格分隔。代表如何改变回调函数列表的行为。
jQuery $.ajax() 和 $.Deferred() 组件的内部会使用 $.Callbacks() 函数,来提供基本的功能。它可以用作定义新组件功能的简易基础。
$.Callbacks() 支持的方法包括
callbacks.add()
,
callbacks.remove()
,
callbacks.fire()
和
callbacks.disable()
.
开始学习
例如,有如下两个方法,分别叫做 fn1 和 fn2:
function fn1( value ){
console.log( value );
}
function fn2( value ){
fn1("fn2 says:" + value);
return false;
}
可以将上述两个方法作为回调函数,并添加到 $.Callbacks 列表中,并按下面的顺序调用它们:
var callbacks = $.Callbacks(); callbacks.add( fn1 ); callbacks.fire( "foo!" ); // outputs: foo! callbacks.add( fn2 ); callbacks.fire( "bar!" ); // outputs: bar!, fn2 says: bar!
这样做的结果是,当构造复杂的回调函数列表时,将会变更很简单。可以根据需要,很方面的就可以向这些回调函数中传入所需的参数。
上面的例子中,我们使用了 $.Callbacks() 的两个方法: .add() 和 .fire()。 .add() 可以向回调函数列表中添加新的回调函数,fire() 可以向回调函数中传递参数,并执行回调函数。
$.Callbacks 支持的另一个方法是 remove(),它可以从回调函数列表中移除指定的回调函数。下面是使用 .remove() 的例子:
var callbacks = $.Callbacks(); callbacks.add( fn1 ); callbacks.fire( "foo!" ); // outputs: foo! callbacks.add( fn2 ); callbacks.fire( "bar!" ); // outputs: bar!, fn2 says: bar! callbacks.remove(fn2); callbacks.fire( "foobar" ); // only outputs foobar, as fn2 has been removed.
支持的标识
flags 参数是 $.Callbacks() 的可选参数,该参数是一个以空格分隔的字符串列表,代表如何改变回调函数列表的行为(例如,$.Callbacks( 'unique stopOnFalse' ))。
可用的标识:
-
once: 保证回调函数列表只能被 .fire() 一次。(就像延迟对象一样) -
memory: 持续保留前一个值,在执行完 .fire() 之后添加的任何回调函数,当再次遇到 .fire() 时,会将“最新保持”的值作为参数,立刻调用最近添加的所有函数,然后再执行回调函数列表中的函数(就像延迟对象一样)。 -
unique: 保证一个回调函数只能被添加一次(也就是说,在回调函数列表中,没有重复的回调函数)。 -
stopOnFalse: 当回调函数返回 false 时,中断调用。
默认情况下,一个回调函数列表就像一个事件回调列表,可以被“调用”多次。
下面是一些理想情况下,使用 flags 的范例:
$.Callbacks( 'once' ):
var callbacks = $.Callbacks( "once" ); callbacks.add( fn1 ); callbacks.fire( "foo" ); callbacks.add( fn2 ); callbacks.fire( "bar" ); callbacks.remove( fn2 ); callbacks.fire( "foobar" ); /* output: foo */
$.Callbacks( 'memory' ):
var callbacks = $.Callbacks( "memory" ); callbacks.add( fn1 ); callbacks.fire( "foo" ); callbacks.add( fn2 ); callbacks.fire( "bar" ); callbacks.remove( fn2 ); callbacks.fire( "foobar" ); /* output: foo fn2 says:foo bar fn2 says:bar foobar */
$.Callbacks( 'unique' ):
var callbacks = $.Callbacks( "unique" ); callbacks.add( fn1 ); callbacks.fire( "foo" ); callbacks.add( fn1 ); // repeat addition callbacks.add( fn2 ); callbacks.fire( "bar" ); callbacks.remove( fn2 ); callbacks.fire( "foobar" ); /* output: foo bar fn2 says:bar foobar */
$.Callbacks( 'stopOnFalse' ):
function fn1( value ){
console.log( value );
return false;
}
function fn2( value ){
fn1("fn2 says:" + value);
return false;
}
var callbacks = $.Callbacks( "stopOnFalse");
callbacks.add( fn1 );
callbacks.fire( "foo" );
callbacks.add( fn2 );
callbacks.fire( "bar" );
callbacks.remove( fn2 );
callbacks.fire( "foobar" );
/*
output:
foo
bar
foobar
*/
由于 $.Callbacks() 可以同时使用多个标识,因此,设置多个标识时,有累积的效果,相当于 "&&"。这意味着,在创建回调函数列表时,可以使用组合标识,例如,同时使用 unique 和 memory($.Callbacks("unique memory")),既保证回调函数列表中函数的唯一性,也可以保证在执行完函数后再添加的函数被调用时,可以使用上次调用时使用的参数。
$.Callbacks( 'unique memory' ):
function fn1( value ){
console.log( value );
return false;
}
function fn2( value ){
fn1("fn2 says:" + value);
return false;
}
var callbacks = $.Callbacks( "unique memory" );
callbacks.add( fn1 );
callbacks.fire( "foo" );
callbacks.add( fn1 ); // repeat addition
callbacks.add( fn2 );
callbacks.fire( "bar" );
callbacks.add( fn2 );
callbacks.fire( "baz" );
callbacks.remove( fn2 );
callbacks.fire( "foobar" );
/*
output:
foo
fn2 says:foo
bar
fn2 says:bar
baz
fn2 says:baz
foobar
*/
jQuery 在延迟对象的 .done() 和 .fail() 中应用 $.Callbacks() 时也使用了标识组合,同时使用了 $.Callbacks('memory once')。
$.Callbacks 方法同样可以被分离出来,这样就可以很方便的创建简单的别名:
var callbacks = $.Callbacks(),
add = callbacks.add,
remove = callbacks.remove,
fire = callbacks.fire;
add( fn1 );
fire( "hello world");
remove( fn1 );
$.Callbacks, $.Deferred 和 Pub/Sub(观察者模式)
pub/sub (观察者模式) 的背后,总的想法是在应用程序中增强松耦合性。并非是在其它对象的方法上的单个对象调用。一个对象作为特定任务或是另一对象的活动的观察者,并且在这个任务或活动发生时,通知观察者。观察者也被叫作订阅者(Subscriber),它指向被观察的对象,既被观察者(Publisher 或 subject)。当事件发生时,被观察者(Publisher)就会通知观察者(subscriber)
作为 $.Callbacks() 的创建组件的一个演示,只使用回调函数列表,就可以实现 Pub/Sub 系统。将 $.Callbacks 作为一个文章队列,可以向下面这样,实现文章的发布和订阅:
var topics = {};
jQuery.Topic = function( id ) {
var callbacks,
method,
topic = id && topics[ id ];
if ( !topic ) {
callbacks = jQuery.Callbacks();
topic = {
publish: callbacks.fire,
subscribe: callbacks.add,
unsubscribe: callbacks.remove
};
if ( id ) {
topics[ id ] = topic;
}
}
return topic;
};
下面的代码可以作为你应用程序的一部分,可以相当简单的完成对感兴趣的文章的发布和订阅事件:
// Subscribers $.Topic( "mailArrived" ).subscribe( fn1 ); $.Topic( "mailArrived" ).subscribe( fn2 ); $.Topic( "mailSent" ).subscribe( fn1 ); // Publisher $.Topic( "mailArrived" ).publish( "hello world!" ); $.Topic( "mailSent" ).publish( "woo! mail!" ); // Here, "hello world!" gets pushed to fn1 and fn2 // when the "mailArrived" notification is published // with "woo! mail!" also being pushed to fn1 when // the "mailSent" notification is published. /* output: hello world! fn2 says: hello world! woo! mail! */
尽管上面的代码很有用,但是可以进一步改进其实现。使用 $.Deferreds,可以保证当特定的任务被完成(或被解决)时,发布者只能向订阅者发布通知。参见下面的示例代码,进一步讨论如何在实践中使用这种情况:
// subscribe to the mailArrived notification $.Topic( "mailArrived" ).subscribe( fn1 ); // create a new instance of Deferreds var dfd = $.Deferred(); // define a new topic (without directly publishing) var topic = $.Topic( "mailArrived" ); // when the deferred has been resolved, publish a // notification to subscribers dfd.done( topic.publish ); // Here the Deferred is being resolved with a message // that will be passed back to subscribers. It's possible to // easily integrate this into a more complex routine // (eg. waiting on an ajax call to complete) so that // messages are only published once the task has actually // finished. dfd.resolve( "its been published!" );