jQuery.Callbacks()


jQuery.Callbacks( flags )返回: Callbacks

描述: 一个多用途的回调列表对象,提供了强大的的方式来管理回调函数列表。

  • 添加的版本: 1.7jQuery.Callbacks( flags )

    • flags
      类型: String
      一个用空格标记分隔的标志可选列表,用来改变回调列表中的行为。

$.Callbacks()的内部提供了jQuery的$.ajax()$.Deferred() 基本功能组件。它可以用来作为类似基础定义的新组件的功能。

$.Callbacks() 支持的方法,包括 callbacks.add(),callbacks.remove(), callbacks.fire() and callbacks.disable().

Getting started(入门)

以下是两个样品的方法命名fn1fn2:

1
2
3
4
5
6
7
8
function fn1( value ) {
console.log( value );
}
function fn2( value ) {
fn1("fn2 says: " + value);
return false;
}

这些可以添加为回调函数作为一个$.Callbacks的列表,并调用如下:

1
2
3
4
5
6
7
8
9
10
var callbacks = $.Callbacks();
callbacks.add( fn1 );
// outputs: foo!
callbacks.fire( "foo!" );
callbacks.add( fn2 );
// outputs: bar!, fn2 says: bar!
callbacks.fire( "bar!" );

这样做的结果是,它使构造复杂的回调列表变得简单,输入值可以通过尽可能多的函数根据需要轻松使用。

用于以上的两个具体的方法: .add().fire() .add() 支持添加新的回调回调列表, 而.fire() 提供了一种用于处理在同一列表中的回调方法的途径.

另一种方法由$.Callbacks.remove(),用于从回调列表中删除一个特定的回调。下面是.remove() 使用的一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var callbacks = $.Callbacks();
callbacks.add( fn1 );
// outputs: foo!
callbacks.fire( "foo!" );
callbacks.add( fn2 );
// outputs: bar!, fn2 says: bar!
callbacks.fire( "bar!" );
callbacks.remove( fn2 );
// only outputs foobar, as fn2 has been removed.
callbacks.fire( "foobar" );

Supported Flags(支持的 Flags)

这个 flags 参数是$.Callbacks()的一个可选参数, 结构为一个用空格标记分隔的标志可选列表,用来改变回调列表中的行为 (比如. $.Callbacks( 'unique stopOnFalse' )).

Possible flags:(可用的 flags:)

  • once: 确保这个回调列表只执行( .fire() )一次(像一个递延 Deferred).
  • memory: 保持以前的值,将添加到这个列表的后面的最新的值立即执行调用任何回调 (像一个递延 Deferred).
  • unique: 确保一次只能添加一个回调(所以在列表中没有重复的回调).
  • stopOnFalse: 当一个回调返回false 时中断调用

默认情况下,回调列表将像事件的回调列表中可以多次触发。

如何在理想情况下应该使用的flags的例子,见下文:

$.Callbacks( "once" ):

1
2
3
4
5
6
7
8
9
10
11
12
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" ):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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" ):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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" ):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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() 支持一个列表的flags(标识)而不仅仅是一个,设置几个flags(标识),有一个累积效应,类似“&&”。这意味着它可能结合创建回调名单,unique确保如果名单已经触发,将有更多的回调调用最新的触发值 (i.e. $.Callbacks("unique memory")).

$.Callbacks( 'unique memory' ):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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
*/

Flag结合体是使用的$.Callbacks()内部的.done().fail()一个递延容器-它们都使用 $.Callbacks('memory once').

$.Callbacks 方法也可以被分离, 为方便起见应该有一个需要定义简写版本:

1
2
3
4
5
6
7
8
var callbacks = $.Callbacks(),
add = callbacks.add,
remove = callbacks.remove,
fire = callbacks.fire;
add( fn1 );
fire( "hello world" );
remove( fn1 );

$.Callbacks, $.Deferred and Pub/Sub

pub / sub(观察者模式)背后的一般思路 是促进应用程序的松散耦合。而比对其他对象的方法调用的单个对象,一个对象,而不是另一个对象的一个特定的任务或活动,并通知当它发生。观察家也被称为订阅者,它指向观察对象。观察者(Publisher)事件发生时通知用户

作为 $.Callbacks() 的创建组件的一个演示,只使用回调函数列表,就可以实现 Pub/Sub 系统。将 $.Callbacks 作为一个文章队列,可以向下面这样,实现文章的发布和订阅:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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;
};

然后,可以很容易的使用这部分应用程序的发布和订阅感兴趣的事件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 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,可以保证当特定的任务被完成(或被解决)时,发布者只能向订阅者发布通知。参见下面的示例代码,进一步讨论如何在实践中使用这种情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 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( "it's been published!" );