Как я могу синхронизировать код javascript, который зависит от ответа на несколько запросов ajax?

#javascript #multithreading #synchronization #thread-safety

#javascript #многопоточность #синхронизация #потокобезопасность

Вопрос:

Обычно я бы использовал функцию обратного вызова, переданную функции ‘jQuery.getJSON’, чтобы что-то сделать после ответа сервера. В этом случае я применил обработчики событий к некоторым элементам ввода, но эти обработчики должны выполняться только после успешного выполнения нескольких запросов ajax. В принципе, мне нужно приостановить выполнение обработчика событий до тех пор, пока не будут доступны некоторые данные, которые я ожидаю.

В многопоточных языках я бы сделал это, используя мьютексы / семафоры, но поскольку javascript однопоточный, мне интересно, возможно ли что-то подобное.

Ответ №1:

Один из ручных способов сделать это — поместить ваши вызовы AJAX в очередь в массив, а затем подсчитать количество полученных вами ответов и подождать, пока это количество не совпадет с размером вашей исходной очереди (или, альтернативно, вывести вызов из очереди, когда ответ завершен, и вы знаете, что у вас есть все, когда очередь имеет размер 0).

Вам нужно было бы проверить, готовы ли вы продолжить вызов setTimeout.

В качестве альтернативы вы можете проверить отложенную поддержку в jQuery 1.5

РЕДАКТИРОВАТЬ: быстрый и грязный пример ручного подхода:

 var remoteCallA = function(){
    $.getJSON('someurl', function(){
        success  ;
    });
};

var remoteCallB = function(){ 
    // etc
};

var whenAllDone = function(){
    // do something when everything is done
};

var checkAllDone = function(){
    if(success === remoteCalls.length){
        whenAllDone();
    } 
    else{ 
        setTimeout(checkAllDone, 1000);
    }
};

var remoteCalls = [remoteCallA, remoteCallB];
var success = 0;
for(var i = 0, length = remoteCalls.length; i  ){
    remoteCalls[i]();
}

checkAllDone();
  

Комментарии:

1. Хм, меня интересует функция ‘setTimeout’, которая может быть тем, что мне нужно. В приведенном вами примере, допустим, вы использовали небольшой тайм-аут (например, 20 миллисекунд), не станет ли рекурсия слишком глубокой? Это может вызвать переполнение стека.

2. @Thiado На самом деле это не рекурсия, потому что вызов setTimeout() возвращается немедленно, и функция завершается. Он просто сообщает браузеру «Эй, через 1000 мс запустите это».

Ответ №2:

javascript основан на событиях, поэтому один из подходов заключается в том, чтобы генерировать событие каждый раз, когда скоординированный xhr получает свой ответ. Обработчик событий отслеживает ответы и продолжается только тогда, когда все они возвращаются.

Или вы можете сделать то же самое без событий, просто вызвав метод напрямую и координируя ответы там….

Ответ №3:

Я могу предложить вам грязное решение. Создайте функцию, которую вы хотите выполнить, как только все запросы вернутся. Создайте другую функцию для выполнения отправки. Точно так же, как семафор / мьютекс, создайте переменную «синхронизация». Увеличивайте переменную для каждого из вызовов. Затем в функции отправки уменьшите переменную и, если она равна нулю, выполните нужную функцию. Примените функцию отправки в качестве обработчика событий для возврата ajax (если у вас уже есть обработчики, которые вы не хотите приостанавливать, поместите ее в конец каждого существующего обработчика).

Затем подумайте о более элегантном решении.