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!" );