jQuery.Callbacks( flags )Возвращает: Callbacks
Описание: Объект списка обратных вызовов общего назначения, предоставляющий мощный способ управления списками обратных вызовов.
-
версия добавлена: 1.7jQuery.Callbacks( flags )
- flagsТип: СтрокаНеобязательный список флагов, разделённых пробелами, которые изменяют поведение списка обратных вызовов.
-
Функция $.Callbacks() внутренне используется для обеспечения базовой функциональности компонентов jQuery $.ajax() и $.Deferred(). Её можно использовать в качестве аналогичной базы для определения функциональности новых компонентов.
$.Callbacks() поддерживает ряд методов, включая callbacks.add(), callbacks.remove(), callbacks.fire() и callbacks.disable().
Начало работы
Ниже приведены два примера методов с именами fn1 и fn2:
function fn1( value ) {
console.log( value );
}
function fn2( value ) {
console.log( "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(). Метод .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 — это необязательный аргумент к $.Callbacks(), представляющий собой список разделённых пробелами строк, которые изменяют поведение списка обратных вызовов (например, $.Callbacks( "unique stopOnFalse" )).
Возможные флаги:
-
once: Обеспечивает, что список обратных вызовов может быть вызван только один раз (как Deferred). -
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() поддерживает список флагов, а не только один, установка нескольких флагов имеет кумулятивный эффект, аналогичный «&&». Это означает, что можно комбинировать флаги, чтобы создать списки обратных вызовов, которые, например, являются как уникальными, так и обеспечивают, что если список уже был вызван, добавление дополнительных обратных вызовов вызовет его с последним значением вызова (то есть $.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
*/ Комбинации флагов с $.Callbacks() используются внутри jQuery для функций .done() и .fail() в Deferred — обе из которых используют $.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 (Publish/Subscribe, или паттерн наблюдателя) — это содействие слабой связанности в приложениях. Вместо того, чтобы отдельные объекты вызывали методы других объектов, объект вместо этого подписывается на определённую задачу или действие другого объекта и получает уведомление при её выполнении. Наблюдатели также называются подписчиками, а объект, за которым ведётся наблюдение, называется издателем (или субъектом). Издатели уведомляют подписчиков о событиях.
Для демонстрации возможностей создания компонентов $.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!" );