jQuery.Callbacks()


jQuery.Callbacks( flags )返回: Callbacks

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

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

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

入门

以下是两个名为 fn1fn2 的示例方法

1
2
3
4
5
6
7
8
function fn1( value ) {
console.log( value );
}
function fn2( value ) {
console.log( "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" );

支持的标志

flags 参数是 $.Callbacks() 的可选参数,结构为一系列空格分隔的字符串,这些字符串会改变回调列表的行为(例如 $.Callbacks( "unique stopOnFalse" ))。

可能的标志

  • once: 确保回调列表只能被触发一次(类似于 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() 支持标志列表而不仅仅是一个标志,所以设置多个标志具有类似于“&&”的累积效果。这意味着可以组合标志来创建回调列表,例如,既是唯一的确保如果列表已经触发,添加更多回调将使用最新触发的值进行调用(即 $.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
*/

在 jQuery 内部,$.Callbacks() 的标志组合用于 Deferred 上的 .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 和 Pub/Sub

发布/订阅(Publish/Subscribe,或观察者模式)背后的核心思想是促进应用程序中的松耦合。一个对象不再直接调用另一个对象的方法,而是订阅另一个对象的特定任务或活动,并在其发生时收到通知。观察者也称为订阅者,我们将被观察的对象称为发布者(或主题)。发布者在事件发生时通知订阅者。

为了演示 $.Callbacks() 的组件创建能力,可以使用仅包含回调列表的方式实现一个 Pub/Sub 系统。使用 $.Callbacks 作为主题队列,可以按如下方式实现一个用于发布和订阅主题的系统

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