Ожидание завершения нескольких асинхронных вызовов перед продолжением
Итак, у меня есть страница, которая загружается и через jquery.сделать несколько запросов, чтобы заполнить выпадающие списки с их значениями.
$(function() {
LoadCategories($('#Category'));
LoadPositions($('#Position'));
LoadDepartments($('#Department'));
LoadContact();
};
затем он вызывает LoadContact (); который выполняет другой вызов, и когда он возвращает, он заполняет все поля в форме. Проблема в том, что часто выпадающие списки не все заполнены, и поэтому он не может установить их в правильное значение.
то, что мне нужно, чтобы быть в состоянии сделать, это как-то иметь LoadContact только выполнить один раз другие методы завершены и обратные вызовы выполнены.
но я не хочу ставить кучу флагов в конце выпадающих обратных вызовов населения, которые я затем проверяю, и должен иметь рекурсивную проверку вызовов setTimeout перед вызовом LoadContact ();
есть ли что-то в jQuery, что позволяет мне сказать: "выполните это, когда все это будет сделано."?
Подробнее
Я думаю что-то вдоль этих линии
$().executeAfter(
function () { // When these are done
LoadCategories($('#Category'));
LoadPositions($('#Position'));
LoadDepartments($('#Department'));
},
LoadContact // Do this
);
...ему нужно будет отслеживать вызовы ajax, которые происходят во время выполнения методов, и когда все они будут завершены, вызовите LoadContact;
если бы я знал, как перехватить ajax, которые создаются в этой функции, я, вероятно, мог бы написать расширение jQuery для этого.
Мое Решение
;(function($) {
$.fn.executeAfter = function(methods, callback) {
var stack = [];
var trackAjaxSend = function(event, XMLHttpRequest, ajaxOptions) {
var url = ajaxOptions.url;
stack.push(url);
}
var trackAjaxComplete = function(event, XMLHttpRequest, ajaxOptions) {
var url = ajaxOptions.url;
var index = jQuery.inArray(url, stack);
if (index >= 0) {
stack.splice(index, 1);
}
if (stack.length == 0) {
callback();
$this.unbind("ajaxComplete");
}
}
var $this = $(this);
$this.ajaxSend(trackAjaxSend)
$this.ajaxComplete(trackAjaxComplete)
methods();
$this.unbind("ajaxSend");
};
})(jQuery);
это привязывается к событию ajaxSend во время вызова методов и сохраняет список URL-адресов (нужен уникальный идентификатор, хотя), которые называются. Затем он освобождается от ajaxSend, поэтому отслеживаются только те запросы, которые нас волнуют. Он также связывается с ajaxComplete и удаляет элементы из стека по мере их возврата. Когда стек достигает нуля, он выполняет наш обратный вызов и отменяет привязку события ajaxComplete.
4 ответов:
можно использовать
.ajaxStop()такой:$(function() { $(document).ajaxStop(function() { $(this).unbind("ajaxStop"); //prevent running again when other calls finish LoadContact(); }); LoadCategories($('#Category')); LoadPositions($('#Position')); LoadDepartments($('#Department')); });Это будет выполняться, когда все текущие запросы будут завершены, а затем отменить привязку, чтобы он не запускался, если будущие вызовы ajax на странице выполняются. Кроме того, не забудьте поставить его перед вызовами ajax, чтобы он был привязан достаточно рано, это более важно с
.ajaxStart(), но лучше всего делать это с обоими.
расширения Тома Лианза это,
$.when()сейчас гораздо лучший способ сделать это, чем с помощью.ajaxStop().единственное предостережение заключается в том, что вам нужно быть уверенным, что асинхронные методы, которые вам нужно ждать, вернут a
Deferred object. К счастью, вызовы jQuery ajax уже делают это по умолчанию. Таким образом, чтобы реализовать сценарий из вопроса, методы, которые нужно ждать, будут выглядеть примерно так:function LoadCategories(argument){ var deferred = $.ajax({ // ajax setup }).then(function(response){ // optional callback to handle this response }); return deferred; }затем чтобы вызвать LoadContact () после того, как все три вызова ajax вернулись и, возможно, выполнили свои собственные индивидуальные обратные вызовы:
// setting variables to emphasize that the functions must return deferred objects var deferred1 = LoadCategories($('#Category')); var deferred2 = LoadPositions($('#Position')); var deferred3 = LoadDepartments($('#Department')); $.when(deferred1, deferred2, deferred3).then(LoadContact);
Если вы находитесь на Jquery 1.5 или более поздней версии, я подозреваю, что отложенный объект - ваш лучший выбор: http://api.jquery.com/category/deferred-object/
вспомогательный метод, когда, также довольно приятно: http://api.jquery.com/jQuery.when/
но я не хочу ставить кучу флагов в конце выпадающих обратных вызовов населения, которые я затем проверяю, и должен иметь рекурсивную проверку вызовов setTimeout перед вызовом LoadContact ();
Нет необходимости в setTimeout. Вы просто проверяете в каждом обратном вызове, что все три списка заполнены (или лучше настроить счетчик, увеличить его в каждом обратном вызове и ждать, пока он не будет равен 3), а затем вызвать LoadContact из обратного вызова. Кажется, довольно легко мне.ajaxStop подход может работать, я просто не очень хорошо знаком с ним.
Comments