Подождите, пока все запросы JQuery Ajax будут выполнены? - PullRequest
623 голосов
/ 14 сентября 2010

Как заставить функцию ждать, пока все запросы jQuery Ajax будут выполнены внутри другой функции?

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

Ответы [ 22 ]

1 голос
/ 05 октября 2018

$.when у меня не работает, callback(x) вместо return x работал как описано здесь: https://stackoverflow.com/a/13455253/10357604

1 голос
/ 28 августа 2017

Я настоятельно рекомендую использовать $. When () , если вы начинаете с нуля.

Несмотря на то, что у этого вопроса более миллиона ответов, я все равно не нашел ничего полезного для своего случая. Допустим, вам приходится иметь дело с существующей кодовой базой, которая уже делает несколько вызовов ajax и не хочет вводить сложность обещаний и / или переделывать все это.

Мы можем легко воспользоваться функциями jQuery .data, .on и .trigger, которые были частью jQuery с самого начала.

Codepen

Хорошая вещь о моем решении:

  • очевидно, от чего точно зависит обратный вызов

  • функция triggerNowOrOnLoaded не заботится, загружены ли уже данные или мы все еще ждем их

  • очень просто подключить его к существующему коду

$(function() {

  // wait for posts to be loaded
  triggerNowOrOnLoaded("posts", function() {
    var $body = $("body");
    var posts = $body.data("posts");

    $body.append("<div>Posts: " + posts.length + "</div>");
  });


  // some ajax requests
  $.getJSON("https://jsonplaceholder.typicode.com/posts", function(data) {
    $("body").data("posts", data).trigger("posts");
  });

  // doesn't matter if the `triggerNowOrOnLoaded` is called after or before the actual requests 
  $.getJSON("https://jsonplaceholder.typicode.com/users", function(data) {
    $("body").data("users", data).trigger("users");
  });


  // wait for both types
  triggerNowOrOnLoaded(["posts", "users"], function() {
    var $body = $("body");
    var posts = $body.data("posts");
    var users = $body.data("users");

    $body.append("<div>Posts: " + posts.length + " and Users: " + users.length + "</div>");
  });

  // works even if everything has already loaded!
  setTimeout(function() {

    // triggers immediately since users have been already loaded
    triggerNowOrOnLoaded("users", function() {
      var $body = $("body");
      var users = $body.data("users");

      $body.append("<div>Delayed Users: " + users.length + "</div>");
    });

  }, 2000); // 2 seconds

});

// helper function
function triggerNowOrOnLoaded(types, callback) {
  types = $.isArray(types) ? types : [types];

  var $body = $("body");

  var waitForTypes = [];
  $.each(types, function(i, type) {

    if (typeof $body.data(type) === 'undefined') {
      waitForTypes.push(type);
    }
  });

  var isDataReady = waitForTypes.length === 0;
  if (isDataReady) {
    callback();
    return;
  }

  // wait for the last type and run this function again for the rest of the types
  var waitFor = waitForTypes.pop();
  $body.on(waitFor, function() {
    // remove event handler - we only want the stuff triggered once
    $body.off(waitFor);

    triggerNowOrOnLoaded(waitForTypes, callback);
  });
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<body>Hi!</body>
1 голос
/ 04 февраля 2016

Также вы можете использовать async.js .

Я думаю, что это лучше, чем $ .when, потому что вы можете объединить все виды асинхронных вызовов, которые не поддерживают обещания из коробки, такие как тайм-ауты, вызовы SqlLite и т. Д., А не только запросы ajax.

1 голос
/ 21 мая 2013

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

        //multiple ajax calls above
        var callback = function () {
            if ($.active !== 0) {
                setTimeout(callback, '500');
                return;
            }
            //whatever you need to do here
            //...
        };
        callback();
1 голос
/ 19 февраля 2012

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

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

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++) { //append logic to invoke callback function once all the ajax calls are completed, in success handler.
    succ = ajaxObjs[i]['success'];
    ajaxObjs[i]['success'] = function(data) { //modified success handler
      if (succ) {
        succ(data);
      }
      ajaxCount--;
      if (ajaxCount == 0) {
        fn(); //modify statement suitably if you want 'this' keyword to refer to another object
      }
    };
    $.ajax(ajaxObjs[i]); //make ajax call
    succ = null;
  };

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

function doSomething() {
  // variable declarations
  untilAjax([{
    url: 'url2',
    dataType: 'json',
    success: function(data) {
      //do something with success data
    }
  }, {
    url: 'url1',
    dataType: 'json',
    success: function(data) {
      //do something with success data
    }
  }, {
    url: 'url2',
    dataType: 'json',
    success: function(response) {
      //do something with success data
    }
  }], function() {
    // logic after all the calls are completed.
  });
}
1 голос
/ 16 ноября 2018

Чтобы расширить ответ Алекса, у меня есть пример с переменными аргументами и обещаниями.Я хотел загрузить изображения через ajax и отобразить их на странице после того, как они все загрузятся.

Для этого я использовал следующее:

let urlCreator = window.URL || window.webkitURL;

// Helper function for making ajax requests
let fetch = function(url) {
    return $.ajax({
        type: "get",
        xhrFields: {
            responseType: "blob"
        },
        url: url,
    });
};

// Map the array of urls to an array of ajax requests
let urls = ["https://placekitten.com/200/250", "https://placekitten.com/300/250"];
let files = urls.map(url => fetch(url));

// Use the spread operator to wait for all requests
$.when(...files).then(function() {
    // If we have multiple urls, then loop through
    if(urls.length > 1) {
        // Create image urls and tags for each result
        Array.from(arguments).forEach(data => {
            let imageUrl = urlCreator.createObjectURL(data[0]);
            let img = `<img src=${imageUrl}>`;
            $("#image_container").append(img);
        });
    }
    else {
        // Create image source and tag for result
        let imageUrl = urlCreator.createObjectURL(arguments[0]);
        let img = `<img src=${imageUrl}>`;
        $("#image_container").append(img);
    }
});

Обновлен для работы как для одного, так и для несколькихURL: https://jsfiddle.net/euypj5w9/

0 голосов
/ 12 января 2016

Я нашел простой способ, используя shift()

function waitReq(id)
{
  jQuery.ajax(
  {
    type: 'POST',
    url: ajaxurl,
    data:
    {
      "page": id
    },
    success: function(resp)
    {
      ...........
      // check array length if not "0" continue to use next array value
      if(ids.length)
      {
        waitReq(ids.shift()); // 2
      )
    },
    error: function(resp)
    {
      ....................
      if(ids.length)
      {
        waitReq(ids.shift());
      )
    }
  });
}

var ids = [1, 2, 3, 4, 5];    
// shift() = delete first array value (then print)
waitReq(ids.shift()); // print 1
0 голосов
/ 09 марта 2014

Решение от Алекса работает отлично. Та же концепция, но использующая ее немного по-другому (когда количество вызовов заранее неизвестно)

http://garbageoverflow.blogspot.com/2014/02/wait-for-n-or-multiple-or-unknown.html

0 голосов
/ 02 марта 2012

Мое решение заключается в следующем

var request;
...
'services': {
  'GetAddressBookData': function() {
    //This is the primary service that loads all addressbook records 
    request = $.ajax({
      type: "POST",
      url: "Default.aspx/GetAddressBook",
      contentType: "application/json;",
      dataType: "json"
    });
  },

  ...

  'apps': {
    'AddressBook': {
      'data': "",
      'Start': function() {
          ...services.GetAddressBookData();
          request.done(function(response) {
            trace("ajax successful");
            ..apps.AddressBook.data = response['d'];
            ...apps.AddressBook.Filter();
          });
          request.fail(function(xhr, textStatus, errorThrown) {
            trace("ajax failed - " + errorThrown);
          });

Работал довольно хорошо. Я пробовал много разных способов сделать это, но я нашел, что это самый простой и наиболее пригодный для повторного использования. Надеюсь, это поможет

0 голосов
/ 14 июня 2011

Я встретил эту проблему и создал общий плагин jquery_counter для ее решения: https://bitbucket.org/stxnext/jquery_counter/

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