#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 (если у вас уже есть обработчики, которые вы не хотите приостанавливать, поместите ее в конец каждого существующего обработчика).
Затем подумайте о более элегантном решении.