Не удается заставить jQuery $.ajax () работать полностью синхронно

#javascript #jquery

#javascript #jquery

Вопрос:

ОБНОВЛЕНИЕ Следуя предложению @ Ryan Olds включить setTimeout в обратный вызов, я должен уточнить, что в моем производственном коде я вызываю несколько URL-адресов для получения данных json с нескольких сайтов. (Обновил код JavaScript ниже).

Возможно ли иметь только несколько таймаутов, разбросанных по всей этой функции?


У меня есть самозапускающаяся функция updateFunction следующим образом:

 (function update() {
  $.ajax({
    type: 'GET',
    url: "http://myexample.com/jsondata",
    dataType: 'json',
    success: function (data) {
      // do some callback stuff
    },
    async: false
  });

 $.ajax({
    type: 'GET',
    url: "http://myexample2.com/jsondata2",
    dataType: 'json',
    success: function (data) {
      // do some further callback stuff
    },
    async: false
  });

  setTimeout(update, 2000);
})();
  

Чего я ожидал от этого кода

Я надеялся, что эта функция перейдет к целевому URL и дождется результата, а затем выполнит успешный обратный вызов. Тогда (и только тогда) не удастся установить 2-секундный тайм-аут для повторного вызова функции.

Что, похоже, происходит вместо

Вместо этого выполняется код запроса GET, и до обработки ответа уже установлен тайм-аут.

Чего мне не хватает? Как я могу сделать это полностью синхронным?

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

1. Вы могли бы поместить setTimeout внутри успешного обратного вызова для вызова AJAX, это одно из предложений. Вы также могли бы использовать setInterval вместо setTimeout и вызывать его после основного объявления.

Ответ №1:

На вашем месте я бы воспользовался поддержкой jQuery для отложенных действий.

 (function update() {
    $.when($.ajax({
        type: 'GET',
        url: "http://myexample.com/jsondata",
        dataType: 'json',
        success: function (data) {
            // do some callback stuff
        }
    }), $.ajax({
        type: 'GET',
        url: "http://myexample2.com/jsondata2",
        dataType: 'json',
        success: function (data) {
            // do some further callback stuff
        }
    }), $.ajax({
        // more requests as you like
    })).then(function() {
        // when all the requests are complete
        setTimeout(update, 2000);
    });
}());
  

Гораздо приятнее, ИМХО, чем возиться с синхронными запросами. Действительно, если запросы являются междоменными, это практически ваш единственный вариант.

Смотрите

Ответ №2:

Перенесите время ожидания на обратный вызов с успехом. Запрос синхронен, казалось бы, обратный вызов — нет.

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

1. @Ryan — просто обновил мой вопрос, поскольку на самом деле он недостаточно прояснил. Возможно ли иметь только несколько таймаутов, разбросанных по всей этой функции?

2. Должны ли запросы выполняться в определенной последовательности?

3. В идеале они бы это сделали, хотя на практике не было бы проблемой, если бы все они возвращались в разное время — при условии, что цикл не повторяется, пока все они не вернутся

4. Нет, я не думаю, что запросы синхронны. Это междоменные запросы, что означает, что jQuery собирается использовать JSONP, и это всегда асинхронно.

5. Вам нужно будет реализовать счетчик в update (), который увеличивается и проверяется при каждом из обратных вызовов. Только после завершения обоих обратных вызовов вызывается следующий setTimeout. Если вы этого не сделаете, вы создадите условие гонки.

Ответ №3:

Я бы изменил настройку следующим образом:

 function update() {
  $.ajax({
    type: 'GET',
    url: "http://myexample.com/jsondata",
    dataType: 'json',
    success: function (data) {
      // do some callback stuff
    },
    async: false
  });

 $.ajax({
    type: 'GET',
    url: "http://myexample2.com/jsondata2",
    dataType: 'json',
    success: function (data) {
      // do some further callback stuff
    },
    async: false
  });
}

setInterval(update, 2000);

update(); // only necessary if you can't wait 2 seconds before 1st load.
  

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

1. Мне нужно было бы проверить, но я не знаю, приостанавливается ли setInterval / setTimeout во время синхронных запросов. Что, если запросы занимают больше 2 секунд? Вы вызываете отставание.

Ответ №4:

Вы не можете сделать это полностью синхронным, потому что вы настраиваете вызовы в альтернативные домены. Это делается (внутри jQuery) путем создания <script> тегов и добавления их в документ. Браузеры выполняют эти вызовы асинхронно, и все. Вы не можете отправлять обычные xhr-запросы к доменам, отличным от вашего собственного.

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

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

1. Просто для пояснения, как упоминалось @Ryan Olds — не было бы проблемой, если бы все они возвращались в разное время — при условии, что цикл не повторяется, пока все они не вернутся. Я подумал, что сделать запросы синхронными было бы лучшим способом продвижения вперед на основе этого требования.

2. @beardtwizzle сейчас есть лучшие способы сделать это, как описывает @lonesomeday в своем ответе 🙂

Ответ №5:

Я не думаю, что async: false работает с междоменными запросами.

Из документации: async Boolean По умолчанию: true По умолчанию все запросы отправляются асинхронно (т. Е. по умолчанию установлено значение true). Если вам нужны синхронные запросы, установите для этого параметра значение false. Междоменные запросы и запросы типа данных «jsonp» не поддерживают синхронную работу. Обратите внимание, что синхронные запросы могут временно блокировать браузер, отключая любые действия, пока запрос активен.

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