JavaScript: Синхронизация асинхронных функций

2010-12-29

Допустим у нас есть несколько асинхронных функций, и нам необходимо выполнить какое-то действие только после того, как все эти асинхронные функции вернут результаты.

Пример, когда это может быть необходимо: нужно с помощью аякса несколькими запросами вытащить различного рода информацию с сервера, потом на стороне клиента её проанализировать и вывести результат для пользователя.
Конечно, можно было бы запускать каждый новый запрос к серверу только по окончанию предыдущего, но это не оптимально и может занять на много больше времени.
Есть много методов решения этой проблемы, но я хочу описать всего один из них, который мне больше всего нравится.

Идея такова:
1) мы создаём глобальный счетчик, который содержит общее число асинхронных функции;
2) запускаем все асинхронные функции на выполнение одновременно;
3) когда любая из этих функций завершается, она вызывает общую функцию, которая отнимает от глобального счетчика единицу и проверят его на равность нулю;
4) если глобальный счетчик равен нулю — это значит, что все асинхронные функции завершили работу, по-этому можно продолжать выполнение.

Рассмотрим пример:
Допустим у нас есть 3 независимых асинхронных функции:

function ajax1(url, callback) {...};
function ajax2(url, callback) {...};
function ajax3(url, callback) {...};

По завершению которых, должен построится отчет функцией:

function report() {...};

Наш код будет выглядеть примерно так:

// По приведенной идеи, создаем глобальную переменную:
var ajaxFunctionsAmount = 3;
// Создаем функцию, которая будет контролировать общее завершение выполнения:
function tryFinish() {
// Отнимаем единицу от счётчика
ajaxFunctionsAmount --;
// Проверяем на равность нулю
if(ajaxFunctionsAmount === 0) {
// Если счётчик равен нулю, значит все функции выполнены и мы можем строить отчёт
report();
}
}
// Теперь вызываем все наши асинхронные функции
// и добавляем им в качестве функции возврата tryFinish()
ajax1("http://url1", tryFinish);
ajax2("http://url2", tryFinish);
ajax3("http://url3", tryFinish);

Вот и всё.

Конечно, этот метод можно как угодно модифицировать, улучшать, изменять, но основная идея подхода — создание счётчика, который ведёт обратный отчет асинхронных функций.
Таким вот образом можно синхронизировать асинхронные функции.



Добавить комментарий