Задача
Допустим вы хотите выполнить два или более 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, за оставленное мнение и хайлайт))