Задача
Допустим вы хотите выполнить два или более AJAX запроса на сервер и вызвать функцию после того, как все они будут закончены.
Небольшая загвоздка в том, что вы не знаете, какой из этих запросов будет закончен первым и не знаете, на кого вешать callback.
Можно завести глобальную переменную и по окончании каждого запроса проверять, завершился ли другой запрос.
Собственно, этим и занимается мой небольшой класс WaitSync =)
WaitSync.js
Пользоваться элементарно просто:
1. Создаем объект типа WaitSync, передав в конструктор callback функцию, которая будет вызвана после того, как отработают нужные задачи.
var vulture = new WaitSync(function () { console.debug('Start eating: ', arguments); });
2. Вместо простого
$.getJSON( 'savannah/get_prey', function (data) { console.log('... prey found: ' + data); } ); $.getJSON( 'savannah/get_other_predators', function () { console.log('... predators are done eating'); } );
«заворачиваем» задачи в метод .wrap
$.getJSON( 'savannah/get_prey', vulture.wrap( function (data) { console.log('... prey found: ' + data); } ) ); $.getJSON( 'savannah/get_other_predators', vulture.wrap( function () { console.log('... predators are done eating'); } ) );
3. Все =) Как только будут выполнены оба AJAX запроса, стервятник начнет есть.
Как это работает?
Когда вы создаете объект WaitSync, вы передаете в качестве аргумента конструктору
тот самый callback.
Когда вы вызываете метод .wrap и передаете ему функцию, он создает из нее другую функцию, которая делает подсчет и проверку вызовов. В качестве второго аргумента также можно передать контекст (ссылку на объект, к которому можно будет обращаться через this). Если вам это действительно нужно…
То есть, фактически, класс делает за вас то, что вы сделали бы своими руками разок-другой, а потом решили бы написать нечто подобное :)
Именованные/группированные задачи
Предположим, вы делаете ajax запросы и вдобавок хотите обработать ошибки:
var monkeyBusiness = new WaitSync(function () {}); $.ajax({ url: '/cgi-bin/palm-tree', success: function (data) { console.log(' eat bananas :) '); }, error: function (data) { console.log(' eat banana peels :( '); } }); $.ajax({ url: '/cgi-bin/monkey-party', success: function (data) { console.log(' dance :) '); }, error: function (data) { console.log(' make political party :( '); } });
Всегда будет выполнятся либо success, либо error. В случае возникновения любого из них нужно перестать ждать появления второго.
Для этого достаточно просто придумать для задачи идентификатор (строковый или числовой) и передать его первым параметром .wrap
var monkeyBusiness = new WaitSync(function () { console.log('Yay! :(|) End of the day'); }); $.ajax({ url: '/cgi-bin/palm-tree', success: monkeyBusiness.wrap( 'palmTree', function (data) { console.log(' eat bananas :) '); return "banana success"; } ), error: monkeyBusiness.wrap( 'palmTree', function (data) { console.log(' eat banana peels :( '); return "banana failure"; } ) }); $.ajax({ url: '/cgi-bin/monkey-party', success: monkeyBusiness.wrap( 'monkeyParty', function (data) { console.log(' dance :) '); return "success"; } ), error: monkeyBusiness.wrap( 'monkeyParty', function (data) { console.log(' make political party :( '); return "error"; } ) });
Теперь callback выполнится как только мартышка слезет с пальмы, а другие закончат вечеринку.
Бонус!
На самом деле WaitSync собирает еще кое-какую информацию.
В callback передается объект, содержащий немного полезной информации:
var monkeyBusiness = new WaitSync( function (result) { console.log('Tasks were complete in the following order: ' + result.order.join(', ')); console.log('Palm tree: ' + result.data['palmTree']); console.log('Monkey party: ' + result.data['monkeyParty']); } );
В подмассиве order хранится порядок, в котором выполнились задачи.
В подмассиве groupOrder хранится порядок только именованных задач/групп.
В подмассиве data хранятся значения, которые вернули все именнованные задачи.
Заключение
Думаю, такая вещь достаточно редко нужна. В node.js могла бы пригодиться…
В общем, вот =) Пользуйтесь на здоровье!
github.com/TEHEK/waitsync
P.S.: пока писал пост, два раза переписывал API XD
P.P.S.: после того, как опубликовал, заметил топик на ту же самую тему, опубликованный ранее… Спасибо The Shock, за оставленное мнение и хайлайт))
