jQuery.Callbacks()

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

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

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

$.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 );
 
// outputs: foo!
callbacks.fire( "foo!" );
 
callbacks.add( fn2 );
 
// outputs: bar!, fn2 says: bar!
callbacks.fire( "bar!" );

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

用于以上的两个具体的方法: .add() 方法支持将新的回调添加到回调列表,而 .fire() 方法执行添加的功能,并提供一种传递参数的方法,该参数将由同一列表中的回调处理。

另一种方法由 $.Callbacks .remove() ,它具有从回调列表中删除特定回调的功能。

下面是.remove()使用的一个例子:

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

这个 flags 参数是 $.Callbacks() 的一个可选参数,结构为由空格分隔的字符串列表,这些字符串更改了回调列表的行为(比如. $.Callbacks('unique stopOnFalse') ).

可用的 flags:

  • once :确保回调列表只能被触发一次(如延迟)
  • memory :跟踪先前的值,并在使用最新的“已存储”值(如Deferred)立即触发列表后调用添加的任何回调。
  • 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() 支持一个列表的flags(标识)而不仅仅是一个,设置几个flags(标识),有一个累积效应,类似“&&”。这意味着可以组合标志来创建回调列表,这两个列表都是唯一的,并确保列表是否已被触发,添加更多回调将使用最新的触发值(即 $.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
*/

Flag结合体是使用的 $.Callbacks() 内部的 .done() .fail() 一个递延容器-它们都使用 $.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 and Pub/Sub

pub/sub (发布/订阅,或观察者模式)背后的总体思想是促进应用程序之间的松耦合。一个对象而不是单个对象调用其他对象的方法,而是订阅另一个对象的特定任务或活动,并在该对象发生时得到通知。观察者也称为订阅者,我们将被观察的对象称为发布者(或主题)。事件发生时,发布者会通知订阅者。

为了演示的组件创建功能 $.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( "it's been published!" );