7

Дождаться завершения всех Ajax-запросов jQuery?

1

Как заставить функцию ждать завершения всех jQuery Ajax запросов внутри другой функции?

Вкратце, мне нужно дождаться завершения всех Ajax запросов, прежде чем выполнить следующий шаг. Как это сделать?

5 ответ(ов)

0

ПРИМЕЧАНИЕ: В приведённых выше ответах используется функциональность, которая не существовала на момент написания этого ответа. Я рекомендую использовать jQuery.when() вместо этих подходов, но оставляю ответ для исторических целей.

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

var semaphore  = 0,     // счётчик семафора для ajax-запросов
    all_queued = false; // логический индикатор для случаев, когда первый запрос может завершиться до того, как второй даже начнётся

semaphore++;
$.get('ajax/test1.html', function(data) {
    semaphore--;
    if (all_queued && semaphore === 0) {
        // обрабатываем вашу пользовательскую логику здесь
    }
});

semaphore++;
$.get('ajax/test2.html', function(data) {
    semaphore--;
    if (all_queued && semaphore === 0) {
        // обрабатываем вашу пользовательскую логику здесь
    }
});

semaphore++;
$.get('ajax/test3.html', function(data) {
    semaphore--;
    if (all_queued && semaphore === 0) {
        // обрабатываем вашу пользовательскую логику здесь
    }
});

semaphore++;
$.get('ajax/test4.html', function(data) {
    semaphore--;
    if (all_queued && semaphore === 0) {
        // обрабатываем вашу пользовательскую логику здесь
    }
});

// теперь, когда все ajax-запросы поставлены в очередь, переключаем логический индикатор
all_queued = true;

Если вы хотите, чтобы это работало как {async: false}, но не хотите блокировать браузер, вы можете достичь того же результата с помощью очереди jQuery.

var $queue = $("<div/>");
$queue.queue(function(){
    $.get('ajax/test1.html', function(data) {
        $queue.dequeue();
    });
}).queue(function(){
    $.get('ajax/test2.html', function(data) {
        $queue.dequeue();
    });
}).queue(function(){
    $.get('ajax/test3.html', function(data) {
        $queue.dequeue();
    });
}).queue(function(){
    $.get('ajax/test4.html', function(data) {
        $queue.dequeue();
    });
});

Этот способ позволяет выполнять запросы последовательно, избегая блокировки UI и упрощая обработку завершённых запросов.

0

Небольшое решение может выглядеть следующим образом:

// Определяем количество необходимых Ajax вызовов
var ajaxCalls = 3;
var counter = 0;
var ajaxCallComplete = function() {
    counter++;
    if (counter >= ajaxCalls) {
        // Когда все Ajax вызовы завершены
        // Выполняем что-то, например, скрываем изображения ожидания или вызываем другую функцию
        $('*').css('cursor', 'auto');
    }
};

var loadPersons = function() {
    // Показываем изображение ожидания или что-то другое
    $('*').css('cursor', 'wait');

    var url = global.ctx + '/loadPersons';
    $.getJSON(url, function(data) {
        // Здесь происходят интересные вещи
    })
    .complete(function() { ajaxCallComplete(); });
};

var loadCountries = function() {
    // Выполняем действия
    var url = global.ctx + '/loadCountries';
    $.getJSON(url, function(data) {
        // Здесь дела
    })
    .complete(function() { ajaxCallComplete(); });
};

var loadCities = function() {
    // Выполняем действия
    var url = global.ctx + '/loadCities';
    $.getJSON(url, function(data) {
        // Здесь дела
    })
    .complete(function() { ajaxCallComplete(); });
};

$(document).ready(function() {
    loadPersons();
    loadCountries();
    loadCities();
});

Надеюсь, это будет полезно...

0

jQuery позволяет вам указать, хотите ли вы, чтобы AJAX-запрос выполнялся асинхронно или синхронно. Если вы сделаете AJAX-запросы синхронными, код после запроса не будет выполняться, пока запрос не завершится.

Например:

jQuery.ajax({ 
    async: false,
    // код
});

Однако стоит отметить, что использование синхронных AJAX-запросов не рекомендуется, так как это может блокировать интерфейс пользователя и ухудшить общее восприятие вашего приложения. Лучше использовать асинхронные запросы и обрабатывать результат в коллбэках.

0

Если вам нужно что-то простое, можно использовать такой одноразовый колбек:

// Ваша логика с несколькими AJAX-запросами выше
var callback = function () {
    if ($.active !== 0) {
        setTimeout(callback, 500);
        return;
    }
    // Здесь выполните необходимые действия
    // ...
};
callback();

Этот код проверяет, есть ли активные AJAX-запросы. Если есть, то запланирует повторный вызов функции через 500 миллисекунд. Как только все запросы завершатся, выполнится нужная вам логика.

0

В ответ на вопрос, основываясь на ответе @BBonifield, я написал утилитарную функцию, чтобы семафорная логика не распространялась по всем AJAX-вызовам.

Функция untilAjax — это утилита, которая вызывает колбэк-функцию, когда все AJAX-вызовы завершены.

ajaxObjs — это массив объектов с настройками AJAX [http://api.jquery.com/jQuery.ajax/].

fn — это колбэк-функция.

Вот код функции:

function untilAjax(ajaxObjs, fn) {
  if (!ajaxObjs || !fn) {
    return;
  }
  var ajaxCount = ajaxObjs.length,
    succ = null;

  for (var i = 0; i < ajaxObjs.length; i++) { // добавляем логику для вызова колбэк-функции, когда все AJAX-вызовы завершены, в обработчик 'success'.
    succ = ajaxObjs[i]['success'];
    ajaxObjs[i]['success'] = function(data) { // модифицированный обработчик 'success'
      if (succ) {
        succ(data);
      }
      ajaxCount--;
      if (ajaxCount == 0) {
        fn(); // модифицируйте это выражение, если хотите, чтобы ключевое слово 'this' ссылалось на другой объект
      }
    };
    $.ajax(ajaxObjs[i]); // выполняем AJAX-запрос
    succ = null;
  }
}

Пример использования: функция doSomething использует untilAjax.

function doSomething() {
  // объявления переменных
  untilAjax([{
    url: 'url2',
    dataType: 'json',
    success: function(data) {
      // что-то делаем с успешными данными
    }
  }, {
    url: 'url1',
    dataType: 'json',
    success: function(data) {
      // что-то делаем с успешными данными
    }
  }, {
    url: 'url2',
    dataType: 'json',
    success: function(response) {
      // что-то делаем с успешными данными
    }
  }], function() {
    // логика после завершения всех вызовов.
  });
}

Эта структура позволяет избежать дублирования кода и облегчает обработку нескольких AJAX-запросов, особенно если нужно выполнить действия после их завершения.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь