Несколько одновременных Ajax запросов (с одним обратным вызовом) в jQuery

Предположим, что есть функция на вашем сайте, которая используется всего 5% времени. Эта функция задействует для работы HTML, CSS и JavaScript. Поэтому вы решаете, что вместо размещения этого кода HTML, CSS и JavaScript непосредственно на странице, вы будете использовать Ajax перед выполнением функции.

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

Как это сделать наилучшим образом?

Ajax вызовы в jQuery обеспечивают обратные вызовы:

jQuery

$.ajax({
  statusCode: {
    url: "/feature",
    success: function() {
      // успешное завершение Ajax
    }
  }
});

Или «отложенный» способ, на этот раз с использованием сокращенного метода $.get():

jQuery

$.get("/feature/").done(function() {
  // успешное завершение Ajax 
});

Но тогда нужно выполнить три Ajax запроса, и необходимо подождать, пока все три запроса завершатся перед тем, как делать что-то дальше, поэтому со стороны обратного вызова это смотрится достаточно угловато:

jQuery

// Получаем HTML
$.get("/feature/", function(html) {
  // Получаем CSS
  $.get("/assets/feature.css", function(css) {
    // Получаем JavaScript
    $.getScript("/assets/feature.js", function() {
       // Все готово, поэтому...
       // Добавляем CSS на страницу
       $("<style />").html(css).appendTo("head");
       //Добавляем HTML на страницу
       $("body").append(html);
    });
  });
});

Здесь мы ждем, пока все функции выполнятся, прежде чем добавлять что-либо на страницу. Таким образом, к тому моменту, когда пользователь увидит что-то, все будет уже готово к выполнению. Возможно, некоторым из читателей такое решение не понравится, но я делал подобные вещи ранее.

По крайней мере, это не лишено смысла и работает. В чем же проблема? Медленное выполнение.

Один запрос… ожидаем, пока завершится…, другой запрос… ожидаем, пока завершится… еще запрос…ожидаем, пока завершится…вперед.

Было бы быстрее, если бы могли сделать:

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

Мы можем воспользоваться здесь Deferred /Promises действием. Я уверен, что для многих это материал JavaScript 101, но эти вещи ускользали от меня в течение долгого времени, а более сложный механизм Promise непонятен до сих пор.

В нашем простом примере, мы можем использовать метод jQuery $.when(), который принимает список таких Deferred объектов (все jQuery Ajax методы возвращают Deferred объекты) и затем обеспечить одиночный обратный вызов.

jQuery

$.when(
  // Отложенный объект (возможно Ajax запрос),
  // Отложенный объект (возможно Ajax запрос),
  // Отложенный объект (возможно Ajax запрос)
}.then(function() {
  // Все было решено (или отклонено), делаем, что нужно
});

Таким образом, наш адский callback можно переписать следующим образом:

jQuery

$.when(
  // Получаем HTML
  $.get("/feature/", function(html) {
    globalStore.html = html;
  }),
  // Получаем CSS
  $.get("/assets/feature.css", function(css) {
    globalStore.css = css;
  }),
  // Получаем JS
  $.getScript("/assets/feature.js")
).then(function() {
  // Все готово, поэтому…
  // Добавляем CSS на страницу
  $("<style />").html(globalStore.css).appendTo("head");
  // Добавляем HTML на страницу
  $("body").append(globalStore.html);
});

Другой вариант использования: срезаем вершки

Мой пример использования – это функция, задействованная в 5% случаев. Сделайте страницу легче для 95% пользователей, которые не пользуются этой функцией, а саму функцию создайте такой, чтобы ее можно было сравнительно быстро добавить для тех пользователей, кому она нужна.

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

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

Здорово, сделайте это с помощью нескольких параллельных Ajax вызовов!

Перевод статьи «Multiple Simultaneous Ajax Requests (with one callback) in jQuery» был подготовлен дружной командой проекта Сайтостроение от А до Я.