# jQuery.Callbacks()

所属分类：回调对象 英文文档：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(入门)

以下是两个样品的方法命名`fn1` 和 `fn2`:

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:foofn2 says:foobarfn2 says:barfoobar*/

## `$.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 additioncallbacks.add( fn2 );callbacks.fire( "bar" );callbacks.remove( fn2 );callbacks.fire( "foobar" ); /*output:foobarfn2 says:barfoobar*/

## `$.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:foobarfoobar*/

因为`$.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 additioncallbacks.add( fn2 );callbacks.fire( "bar" );callbacks.add( fn2 );callbacks.fire( "baz" );callbacks.remove( fn2 );callbacks.fire( "foobar" ); /*output:foofn2 says:foobarfn2 says:barbazfn2 says:bazfoobar*/

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 Deferredsvar dfd = $.Deferred(); // define a new topic (without directly publishing)var topic = $.Topic( "mailArrived" ); // when the deferred has been resolved, publish a// notification to subscribersdfd.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!" );