Реальный пиарJavaScriptJquery → Что такое этот новый jQuery.Callbacks Object

Что такое этот новый jQuery.Callbacks Object

В не столь давно вышедшей версии jQuery 1.7 появился новый объект Callbacks, о котором сегодня и пойдёт речь.
В официальной документации jQuery.Callbacks описан, как многоцелевой объект, представляющий собой список функций обратного вызова (callbacks – далее просто колбэков) и мощные инструменты по управлению этим списком.

Я просматривал возможности этого объекта, когда он был ещё только в разработке, и надо сказать, что возможностей у него изначально было немного больше, чем осталось в релизной версии. Например, сейчас отсутствует возможность создания очереди (queue) колбэков, которые вызываются по одному на каждый вызов fire(). Видимо, команда jQuery, решила немного подсократить код, убрав «ненужные/редкоиспользуемые» возможности, чтобы сэкономить в весе библиотеки. Это маленький экскурс в историю Callbacks, но далее я буду описывать только доступные сейчас функции и в конце напишу небольшое возможное улучшение этого объекта.
Назначение

Прежде чем приступить к подробному изучению этого нового объекта jQuery.Callbacks, хочу остановиться на том, для чего же вообще нужен этот объект. Довольно часто в JavaScript коде используются колбэки – функции, которые вызываются при наступлении некоторого события, например, после завершения какого-то действия, самым ярким примером может послужить запрос AJAX. И при этом часто возникает потребность вызвать не одну функцию, а сразу несколько (заранее неизвестно сколько, может быть пару, может быть пару десятков, а может вообще ни одной) – это известный и простой паттерн «Наблюдатель». И вот для таких случаев и оказывается полезен рассматриваемый объект jQuery.Callbacks. В самом jQuery этот объект используется (начиная с версии 1.7) внутри jQuery.Deferred и jQuery.ajax. Также авторы jQuery сделали этот объект общедоступным и задокументировала его, чтобы другие разработчики могли его использовать при реализации собственных компонентов.
Конструктор: jQuery.Callbacks(flags)

Вызовом конструктора создаётся объект callbacks, который имеет ряд методов для управления списком колбэков.
Параметр flags необязательный и позволяет задать параметры работы объекта, возможные значения параметра мы рассмотрим ниже.1 var callbacks = $.Callbacks();

К созданному объекту callbacks мы сможем теперь добавлять функции-колбэки в список, удалять их, вызывать, снова вызывать (если это не было запрещено при создании объекта), проверять статус объекта (был ли уже вызов или ещё нет) с помощью таких методов объекта, как add(), remove(), fire() и пр. Выполняются колбэки, кстати, в порядке их добавления в список.

Отмечу, что это не «настоящий» конструктор экземпляра класса, поэтому использовать оператор new при его вызове не требуется (и даже бессмысленно).

По этой причине не получится проверить, является ли объект экземпляром Callbacks, способом, стандартным для JS:1 if (obj instanceof $.Callbacks) {
2 obj.add(fn);
3 }


Выражение под if всегда возвращает false. Но можно положиться на один из известных методов этого объекта (или сразу на несколько), например, можно проверить так:1 if (obj.fire) {
2 obj.add(fn);
3 }


На самом деле, внутри этой функции создаётся обычный JS-объект с определённым набором методов, которые опираются на своё замыкание – это довольно распространённый в JavaScript способ задания приватных (private) переменных, недоступных вне этого псевдоконструктора.

Также, благодаря такому псевдоконструктору, методы этого объекта никак не зависят от контекста вызова – объекта, которому они принадлежат, а это значит, что их можно смело присваивать в свойства другого объекта, не заботясь о смене контекста, – всё по прежнему будет работать корректно. Это справедливо для всех методов, кроме fire, он как раз таки зависит от контекста, но использует его в качестве контекста выполнения колбэков из списка, т.е. этот метод в ряде случаев не просто можно, а именно нужно присваивать свойствам другого объекта со сменой контекста. Например:1 var c = $.Callbacks(), obj = {};
2 obj.register = c.add;
3 obj.register(function() { console.log('fired'); });
4 c.fire();
5 // output: 'fired'

Флаги

Примечание: далее по тексту под словами «вызов метода fire()» понимается вызов выполнения колбэков из списка в том числе и методом fireWith().

Параметр конструктора flags – это строка, в которой через пробел можно указать флаги – опции, в соответствии с которыми будет работать созданный объект callbacks. Поддерживаются такие флаги:

once – указывает, что список колбэков может быть выполнен только единожды, второй и последующие вызовы метода fire() будут безрезультатны (как это сделано в объекте deferred), если этот флаг не указан, то можно несколько раз вызывать метод fire().

memory – указывает, что необходимо запоминать параметры последнего вызова метода fire() (и выполнения колбэков из списка) и немедленно выполнять добавляемые колбэки с соответствующими параметрами, если они добавляются уже после вызова метода fire() (как это сделано в объекте deferred).

unique – указывает, что каждый колбэк может быть добавлен в список только один раз, повторная попытка добавить колбэк в список ни к чему ни приведёт.

stopOnFalse – указывает, что нужно прекратить выполнение колбэков из списка, если какой-то из них вернул false, в пределах текущей сессии вызова fire(). Следующий вызов метода fire() начинает новую сессию выполнения списка колбэков, и они будут выполняться опять до тех пор, пока один из списка не вернёт false либо пока не закончатся.
Методы

Ниже я приведу список методов с кратким описанием, примеры есть в официальных доках и для некоторых методов в следующем разделе. В общем-то методы довольно просты и ведут себя вполне ожидаемо.

callbacks.add(callbacks) returns: callbacks – добавляет в список колбэки, можно одновременно передавать в аргументах этого метода несколько функций (несколько аргументов) или массивов функций (можно одновременно и то и другое), можно даже вложенные массивы передавать. Все аргументы (или элементы массива), не являющиеся функциями, просто игнорируются. Метод (этот и некоторые далее) возвращает контекст своего вызова, позволяя тем самым организовать цепочку вызовов нескольких методов одного объекта подряд, как это принято в jQuery.

callbacks.remove(callbacks) returns: callbacks – удаляет колбэки из списка, причем даже если колбэк был добавлен дважды, удаление его произойдёт с обеих позиций. Т.о. если вызвать метод удаления некоторого колбэка из списка, то можно быть уверенным, что его в списке больше нет, сколько бы раз его не добавляли. Можно передавать несколько функций одновременно как несколько аргументов, массивы передавать нельзя, все аргументы не функции игнорируются.

callbacks.has(callback) returns: boolean – проверяет, есть ли указанная функция в списке колбэков.

callbacks.empty() returns: callbacks – очищает список колбэков.

callbacks.disable() returns: callbacks – «отключает» объект callbacks, все действия с ним будут безрезультатны. При этом перестают работать вообще все методы: add – ни к чему не приводит, has – всегда возвращает false и пр.

callbacks.disabled() returns: boolean – проверяет, отключен ли объект callbacks, после вызова disable() будет возвращать true.

callbacks.lock() returns: callbacks – фиксирует текущее состояние объекта callbacks относительно параметров и состояния выполнения списка колбэков. Этот метод актулен при использовании флага memory и предназначен для блокирования только последующих вызовов fire(), в остальных случаях он равносилен вызову disable().

Детально этот метод работает так: если флаг memory не указан или ещё ни разу не был вызван метод fire() или последняя сессия выполнения колбэков была прервана возвратом false одним из них, то вызов lock() равносилен вызову disable() (именно он и вызывается внутри) и вызов disabled() в таком случае вернёт true, иначе будут заблокированы только последующие вызовы fire() – они не приведут ни к выполнению колбэков, ни к изменению параметров выполнения добавляемых колбэков (при наличии флага memory).

callbacks.locked() returns: boolean – проверяет, зафиксирован ли объект callbacks методом lock(), также верёт true после вызова disable().

callbacks.fireWith( [context] [, args] ) returns: callbacks – запускает выполнение всех колбэков в списке с указанным контекстом и аргументами. context – указывает контекст выполнения колбэка (объект, доступный через this внутри функции). args – массив (именно массив) аргументов, передаваемых в колбэк.

callbacks.fire( arguments ) returns: callbacks – запускает выполнение всех колбэков в списке с контекстом вызова и аргументами этого метода. arguments – список аргументов (не массив, как в методе fireWith()). Т.е. контекстом вызова и аргументами колбэков будут контекст и аргументы метода fire().

Пример, как можно эквивалентно запустить исполнение колбэков с одинаковыми параметрами и контекстом:01 var callbacks = $.Callbacks(),
02 context = { test: 1 };
03 callbacks.add(function(p, t) { console.log(this.test, p, t); });
04
05 callbacks.fireWith(context, [ 2, 3 ]);
06 // output: 1 2 3
07
08 context.fire = callbacks.fire;
09 context.fire(2, 3);
10 // output: 1 2 3

Колбэки из списка выполняются в том порядке, в котором они в этот список добавлялись. После выполнения колбэков при указанном флаге once список будет очищен, а если при этом не указан флаг memory или выполнение колбэков было прервано возвратом false, то объект callbacks будет отключен методом disable().
Примеры

Давайте посмотрим как работают флаги на примерах. Во всех примерах используются такие функции:1 function fn1( value ){
2 console.log( value );
3 }
4
5 function fn2( value ){
6 fn1("fn2 says:" + value);
7 return false;
8 }

$.Callbacks():01 var callbacks = $.Callbacks();
02 callbacks.add( fn1 );
03 callbacks.fire( "foo" );
04 callbacks.add( fn2 );
05 callbacks.add( fn1 );
06 callbacks.fire( "bar" );
07 callbacks.remove( fn2 );
08 callbacks.fire( "foobar" );
09 console.log(callbacks.disabled());
10
11 /*
12 output:
13 foo
14 bar
15 fn2 says:bar
16 bar
17 foobar
18 foobar
19 false
20 */
Никакие флаги не указали – вполне ожидаемое поведение.
$.Callbacks(‘once’):01 var callbacks = $.Callbacks( "once" );
02 callbacks.add( fn1 );
03 callbacks.fire( "foo" );
04 callbacks.add( fn2 );
05 callbacks.add( fn1 );
06 callbacks.fire( "bar" );
07 callbacks.remove( fn2 );
08 callbacks.fire( "foobar" );
09 console.log(callbacks.disabled());
10
11 /*
12 output:
13 foo
14 true
15 */

Тут всё понятно – один раз выполнили, что было, далее ничего не происходит, что ни делали, т.к. список уже отключен.
$.Callbacks(‘memory’):01 var callbacks = $.Callbacks( "memory" );
02 callbacks.add( fn1 );
03 callbacks.fire( "foo" );
04 callbacks.add( fn2 );
05 callbacks.add( fn1 );
06 callbacks.fire( "bar" );
07 callbacks.remove( fn2 );
08 callbacks.fire( "foobar" );
09 console.log(callbacks.disabled());
10
11 /*
12 output:
13 foo
14 fn2 says:foo
15 foo
16 bar
17 fn2 says:bar
18 bar
19 foobar
20 foobar
21 false
22 */

Здесь, вроде, тоже ничего сложного – после первого выполнения каждое добавление колбэка вызывает его немедленное выполнение, а потом снова вызываем выполнение всего списка. При этом одну функцию мы добавили в список дважды – она дважды и срабатывает.
$.Callbacks(‘unique’):01 var callbacks = $.Callbacks( "unique" );
02 callbacks.add( fn1 );
03 callbacks.fire( "foo" );
04 callbacks.add( fn2 );
05 callbacks.add( fn1 );
06 callbacks.fire( "bar" );
07 callbacks.remove( fn2 );
08 callbacks.fire( "foobar" );
09 console.log(callbacks.disabled());
10
11 /*
12 output:
13 foo
14 bar
15 fn2 says:bar
16 foobar
17 false
18 */

А в этом случае повторное добавление функции fn1 было проигнорировано.
$.Callbacks(’stopOnFalse’):01 var callbacks = $.Callbacks( "stopOnFalse" );
02 callbacks.add( fn1 );
03 callbacks.fire( "foo" );
04 callbacks.add( fn2 );
05 callbacks.add( fn1 );
06 callbacks.fire( "bar" );
07 callbacks.remove( fn2 );
08 callbacks.fire( "foobar" );
09 console.log(callbacks.disabled());
10
11 /*
12 output:
13 foo
14 bar
15 fn2 says:bar
16 foobar
17 foobar
18 false
19 */

Колбэк fn2 прерывает цепочку выполнения, т.к. возвращает false.

Это простые примеры, а теперь давайте попробуем поиграться с комбинациями флагов – будет немного интереснее:
$.Callbacks(‘once memory’):01 var callbacks = $.Callbacks( "once memory" );
02 callbacks.add( fn1 );
03 callbacks.fire( "foo" );
04 callbacks.add( fn2 );
05 callbacks.add( fn1 );
06 callbacks.fire( "bar" );
07 callbacks.remove( fn2 );
08 callbacks.fire( "foobar" );
09 console.log(callbacks.disabled());
10
11 /*
12 output:
13 foo
14 fn2 says:foo
15 foo
16 false
17 */

Видим, что сработали только первый fire() и добавление новых колбэков привело к их немедленному выполнению с параметрами первого fire().
$.Callbacks(‘once memory unique’):01 var callbacks = $.Callbacks( "once memory unique" );
02 callbacks.add( fn1 );
03 callbacks.fire( "foo" );
04 callbacks.add( fn2 );
05 callbacks.add( fn1 );
06 callbacks.fire( "bar" );
07 callbacks.remove( fn2 );
08 callbacks.fire( "foobar" );
09 console.log(callbacks.disabled());
10
11 /*
12 output:
13 foo
14 fn2 says:foo
15 foo
16 false
17 */

Здесь результат тот же, несмотря на то, что мы указали флаг unique и дважды добавляем fn1, – второй раз добавление этой функции в список сработало, потому что при указанном флаге once после выполнения колбэков список очищается, а флаг memory указывает, что последующие добавления колбэков будут приводить к их немедленному выполнению без помещения в список, а так как список пуст – то добавление любой функции всегда уникально. Но этот флаг сыграет свою роль при попытке добавить за раз несколько колбэков, среди которых есть дублирующиеся, если в предыдущем коде изменить 4-ю строку как показано ниже, то fn2 всё равно выполнена будет только один раз (а без флага unique была бы выполнена три раза):1 callbacks.add( fn2, fn2, fn2 );

$.Callbacks(‘once memory stopOnFalse’):01 var callbacks = $.Callbacks( "once memory stopOnFalse" );
02 callbacks.add( fn1 );
03 callbacks.fire( "foo" );
04 callbacks.add( fn2 );
05 callbacks.add( fn1 );
06 callbacks.fire( "bar" );
07 callbacks.remove( fn2 );
08 callbacks.fire( "foobar" );
09 console.log(callbacks.disabled());
10
11 /*
12 output:
13 foo
14 fn2 says:foo
15 true
16 */

Возврат false заблокировал все дальнейшие выполнения колбэков и при наличии флага once вообще привёл к отключению объекта callbacks.

Я не буду рассматривать все возможные комбинации флагов, я постарался выбрать наиболее интересные (не совсем простые) и объяснить поведение callbacks. Остальные комбинации можно протестировать самостоятельно, например, воспользовавшись заготовкой: http://jsfiddle.net/zandroid/JXqzB/


Источник: http://www.linkexchanger.su

Рекомендуем



jQuery примеры - работа с выпадающим списком Поэтому я хочу поделиться с Вами информацией о методах работы с конткретными HTML элементами при помощи jQuery


Что такое Web Storage? Статьи про эту технологию конечно уже существуют, но я, следуя духу блога, попробую объяснить, что такое Web Storage, очень простым языком, с примерами и подробными комментариями к ним


Ненавязчивое (unobtrusive) программирование Простота и удобство их использования привлекли большое сообщество авторов таких расширений; справочник расширений насчитывает уже более ста примеров