Czekać, aż wszystkie żądania Jquery Ajax zostaną wykonane?

Jak sprawić, by funkcja czekała, aż wszystkie żądania Jquery Ajax zostaną wykonane wewnątrz innej funkcji?

Krótko mówiąc, muszę poczekać na wszystkie żądania Ajax do wykonania przed wykonaniem następnego. Ale jak?

Author: Maistrenko Vitalii, 2010-09-14

19 answers

JQuery definiuje teraz funkcję when do tego celu.

Przyjmuje dowolną liczbę obiektów odroczonych jako argumenty i wykonuje funkcję, gdy wszystkie z nich zostaną rozwiązane.

Oznacza to, że jeśli chcesz zainicjować (na przykład) cztery żądania ajax, a następnie wykonać akcję, gdy zostaną wykonane, możesz zrobić coś takiego:

$.when(ajax1(), ajax2(), ajax3(), ajax4()).done(function(a1, a2, a3, a4){
    // the code here will be executed when all four ajax requests resolve.
    // a1, a2, a3 and a4 are lists of length 3 containing the response text,
    // status, and jqXHR object for each of the four ajax calls respectively.
});

function ajax1() {
    // NOTE:  This function must return the value 
    //        from calling the $.ajax() method.
    return $.ajax({
        url: "someUrl",
        dataType: "json",
        data:  yourJsonData,            
        ...
    });
}

Moim zdaniem, to sprawia, że czysta i przejrzysta składnia, i unika angażowania wszelkich zmiennych globalnych, takich jak ajaxStart i ajaxStop, które może mieć niepożądane skutki uboczne w miarę rozwoju strony.

Jeśli nie wiesz z góry, na ile argumentów ajax trzeba czekać (tzn. chcesz użyć zmiennej liczby argumentów), nadal można to zrobić, ale jest to tylko trochę trudniejsze. Zobacz przekazanie tablicy Deferredów do $.when () (a może jQuery .podczas rozwiązywania problemów ze zmienną liczbą argumentów ).

Jeśli potrzebujesz głębszej kontroli nad trybami awarii skryptów ajax itp., możesz zapisać obiekt zwracany przez .when() - jest to obiekt jQuery Promise obejmujący wszystkie oryginalne zapytania ajax. Możesz wywołać .then() lub .fail(), aby dodać szczegółowe procedury obsługi sukcesu/porażki.

 782
Author: Alex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-13 10:32:12

Jeśli chcesz poczekać, aż wszystkie żądania ajax zostaną zakończone w dokumencie, bez względu na to, ile z nich istnieje, po prostu użyj $.ajaxStop Zdarzenie w ten sposób:

  $(document).ajaxStop(function () {
      // 0 === $.active
  });

W tym przypadku nie ma potrzeby zgadywania, ile żądań może być w aplikacji, która może zakończyć się w przyszłości. W niektórych przypadkach żądania ajax mogą być częścią wewnętrznej logiki funkcji, co może być dość skomplikowane( np. wywołanie innych funkcji) i w takim przypadku możesz nie czekać, aż dana funkcja zostanie wykonana z jego cała logika, a nie tylko czekając na ajax Część, aby zakończyć.

$.ajaxStop tutaj może być również powiązany z dowolnym HTML węzłem, który Twoim zdaniem może zostać zmodyfikowany przez ajax.

Ponownie celem tego Handlera jest wiedzieć, kiedy nie ma aktywnego ajax nie wyczyścić lub zresetować czegoś.

P. S. Jeśli nie masz nic przeciwko używaniu składni ES6, możesz użyć Promise.all dla znanych metod ajax. Przykład:

Promise.all([ajax1(), ajax2()]).then(() => {
 // all requests finished successfully
}).catch(() => {
 // all requests finished but one or more failed
})

Ciekawostką jest to, że działa zarówno z żądaniami Promises, jak i $.ajax. Oto jsFiddle demonstrujący ostatni.

 258
Author: Arsen Khachaturyan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-02 10:05:38

Znalazłem dobrą odpowiedź by gnarf moje ja czyli dokładnie to czego szukałem:)

JQuery ajaxQueue

//This handles the queues    
(function($) {

  var ajaxQueue = $({});

  $.ajaxQueue = function(ajaxOpts) {

    var oldComplete = ajaxOpts.complete;

    ajaxQueue.queue(function(next) {

      ajaxOpts.complete = function() {
        if (oldComplete) oldComplete.apply(this, arguments);

        next();
      };

      $.ajax(ajaxOpts);
    });
  };

})(jQuery);

Następnie możesz dodać żądanie ajax do kolejki w następujący sposób:

$.ajaxQueue({
        url: 'page.php',
        data: {id: 1},
        type: 'POST',
        success: function(data) {
            $('#status').html(data);
        }
    });
 30
Author: jamietelin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:54

Uwaga: powyższe odpowiedzi wykorzystują funkcjonalność, która nie istniała w momencie pisania tej odpowiedzi. Zalecam stosowanie jQuery.when() zamiast tych podejść, ale zostawiam odpowiedź dla celów historycznych.

-

Prawdopodobnie poradziłbyś sobie z prostym semaforem zliczającym, chociaż to, jak go zaimplementujesz, zależy od Twojego kodu. Prostym przykładem byłoby coś takiego...

var semaphore  = 0,     // counting semaphore for ajax requests
    all_queued = false; // bool indicator to account for instances where the first request might finish before the second even starts

semaphore++;
$.get('ajax/test1.html', function(data) {
    semaphore--;
    if (all_queued && semaphore === 0) {
        // process your custom stuff here
    }
});

semaphore++;
$.get('ajax/test2.html', function(data) {
    semaphore--;
    if (all_queued && semaphore === 0) {
        // process your custom stuff here
    }
});

semaphore++;
$.get('ajax/test3.html', function(data) {
    semaphore--;
    if (all_queued && semaphore === 0) {
        // process your custom stuff here
    }
});

semaphore++;
$.get('ajax/test4.html', function(data) {
    semaphore--;
    if (all_queued && semaphore === 0) {
        // process your custom stuff here
    }
});

// now that all ajax requests are queued up, switch the bool to indicate it
all_queued = true;

Jeśli chcesz to działać jak {async: false} ale ty nie chciał zablokować przeglądarki, można osiągnąć to samo z kolejki 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();
    });
});
 20
Author: BBonifield,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-20 22:15:02

Użyj zdarzenia ajaxStop.

Na przykład, załóżmy, że masz Ładowanie ... wiadomość podczas pobierania 100 żądań ajax i chcesz ukryć tę wiadomość po załadowaniu.

Z jQuery doc :

$("#loading").ajaxStop(function() {
  $(this).hide();
});

Należy pamiętać, że będzie czekać na wszystkie żądania ajax wykonywane na tej stronie.

 19
Author: olafure,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-05 18:34:49

Małe obejście Jest Takie:

// Define how many Ajax calls must be done
var ajaxCalls = 3;
var counter = 0;
var ajaxCallComplete = function() {
    counter++;
    if( counter >= ajaxCalls ) {
            // When all ajax calls has been done
        // Do something like hide waiting images, or any else function call
        $('*').css('cursor', 'auto');
    }
};

var loadPersons = function() {
        // Show waiting image, or something else
    $('*').css('cursor', 'wait');

    var url = global.ctx + '/loadPersons';
    $.getJSON(url, function(data) {
            // Fun things
    })
    .complete(function() { **ajaxCallComplete();** });
};

var loadCountries = function() {
    // Do things
    var url = global.ctx + '/loadCountries';
    $.getJSON(url, function(data) {
            // Travels
    })
    .complete(function() { **ajaxCallComplete();** });
};

var loadCities = function() {
    // Do things
    var url = global.ctx + '/loadCities';
    $.getJSON(url, function(data) {
            // Travels
    })
    .complete(function() { **ajaxCallComplete();** });
};

$(document).ready(function(){
    loadPersons();
    loadCountries();
    loadCities();
});
Nadzieja może się przydać...
 7
Author: Jesfre,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-26 16:13:01

Javascript jest oparty na zdarzeniach, więc nigdy nie należy czekać , raczej ustawiać Hooki/wywołania

Prawdopodobnie możesz po prostu użyć metod success / complete jquery.ajax

Lub możesz użyć .ajaxComplete :

$('.log').ajaxComplete(function(e, xhr, settings) {
  if (settings.url == 'ajax/test.html') {
    $(this).text('Triggered ajaxComplete handler.');
    //and you can do whatever other processing here, including calling another function...
  }
});

Chociaż powinieneś opublikować pseudokod o tym, jak twoje żądania ajax są wywoływane, aby być bardziej precyzyjnym...

 6
Author: Stefano,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-14 15:07:02

JQuery pozwala określić, czy żądanie ajax ma być asynchroniczne, czy nie. Możesz po prostu synchronizować żądania ajax, a reszta kodu nie zostanie wykonana, dopóki nie powrócą.

Na przykład:

jQuery.ajax({ 
    async: false,
    //code
});
 2
Author: shmuel613,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-21 09:01:17

Możesz również użyć asynchronicznego.js .

Myślę, że to lepsze niż $.kiedy ponieważ można scalić wszystkie rodzaje asynchronicznych połączeń, które nie obsługują obietnic po wyjęciu z pudełka jak timeouts, SQLLite połączeń itp. i nie tylko żądania ajax.

 1
Author: George Mavritsakis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-04 18:32:03

Na podstawie odpowiedzi @BBonifield napisałem funkcję użytkową, dzięki której logika semaforów nie jest rozpowszechniana we wszystkich wywołaniach ajax.

untilAjax to funkcja użytkowa, która wywołuje funkcję zwrotną po zakończeniu wszystkich połączeń Ajax.

ajaxObjs jest tablicą obiektów ustawień ajax [http://api.jquery.com/jQuery.ajax/].

fn jest funkcją callback

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;
  };

Przykład: doSomething funkcja używa 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
Author: Sanjeev Kumar Dangi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-05 19:05:25

Gorąco polecam użycie $.when () {[8] } Jeśli zaczynasz od zera.

Mimo, że to pytanie ma ponad milion odpowiedzi, nadal nie znalazłem niczego użytecznego dla mojej sprawy. Załóżmy, że masz do czynienia z istniejącą bazą kodową, już wykonując niektóre połączenia ajax i nie chcesz wprowadzać złożoności obietnic i / lub ponowić całość.

Możemy łatwo skorzystać z jQuery .data, .on i .trigger funkcje, które są częścią jQuery od na zawsze.

Codepen

Dobra rzecz o moim rozwiązaniu jest:

  • To oczywiste, od czego dokładnie zależy callback

  • Funkcja triggerNowOrOnLoaded nie dba o to, czy dane zostały już załadowane lub nadal na nie czekamy

  • Bardzo łatwo jest podłączyć go do istniejącego kodu

$(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
Author: cilf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-28 11:15:42

$.when nie działa dla mnie, callback(x) zamiast return x działa jak opisano tutaj: https://stackoverflow.com/a/13455253/10357604

 1
Author: thestruggleisreal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-05 10:48:44

Jeśli potrzebujesz czegoś prostego; once and done callback

        //multiple ajax calls above
        var callback = function () {
            if ($.active !== 0) {
                setTimeout(callback, '500');
                return;
            }
            //whatever you need to do here
            //...
        };
        callback();
 0
Author: Fatmuemoo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-21 14:12:03

Spotkałem się z tym problemem i stworzył ogólny plugin jquery_counter, aby go rozwiązać: https://bitbucket.org/stxnext/jquery_counter/

 0
Author: zefciu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-15 16:10:30

Znalazłem prosty sposób, to za pomocą 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
Author: uingtea,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-12 15:39:09

Moje rozwiązanie jest następujące

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);
          });
Zadziałało całkiem nieźle. Próbowałem wiele różnych sposobów, aby to zrobić, ale okazało się, że jest to najprostszy i najbardziej wielokrotnego użytku. Hope it helps
 0
Author: Eric Sean Moore,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-05 18:34:00

Spójrz na moje rozwiązanie:

1.Wstaw tę funkcję (i zmienną) do pliku javascript:

var runFunctionQueue_callback;

function runFunctionQueue(f, index, callback) {

  var next_index = index + 1

  if (callback !== undefined) runFunctionQueue_callback = callback;

  if (f[next_index] !== undefined) {
    console.log(index + ' Next function avalaible -> ' + next_index);
    $.ajax({
      type: 'GET',
      url: f[index].file,
      data: (f[index].data),
      complete: function() {
        runFunctionQueue(f, next_index);
      }
    });
  } else {
    console.log(index + ' Last function');
    $.ajax({
      type: 'GET',
      url: f[index].file,
      data: (f[index].data),
      async: false,
      complete: runFunctionQueue_callback
    });
  }
}

2.Zbuduj tablicę z żądaniami, jak to:

var f = [
           {file: 'file_path', data: {action: 'action', data: 'any_data}},
           {file: 'file_path', data: {action: 'action', data: 'any_data}},
           {file: 'file_path', data: {action: 'action', data: 'any_data}},
           {file: 'file_path', data: {action: 'action', data: 'any_data}}
        ];

3.Utwórz funkcję wywołania zwrotnego:

function Function_callback() {
  alert('done');
}

4.Wywołanie funkcji runFunctionQueue z parametrami:

runFunctionQueue(f, 0, QuestionInsert_callback);
// first parameter: array with requests data
// second parameter: start from first request
// third parameter: the callback function
 0
Author: Briganti,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-05 18:54:44

Rozwiązanie podane przez Alexa działa dobrze. Ta sama koncepcja, ale użycie jej w nieco inny sposób (gdy liczba połączeń nie jest znana z góry)

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

 -1
Author: athap,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-09 02:45:37

Spróbuj w ten sposób. wykonaj pętlę wewnątrz funkcji java script, aby poczekać do zakończenia połączenia ajax.

function getLabelById(id)
{
    var label = '';
    var done = false;
    $.ajax({
       cache: false,
       url: "YourMvcActionUrl",
       type: "GET",
       dataType: "json",
       async: false,
       error: function (result) {
         label='undefined';
         done = true;
        },
       success: function (result) {
            label = result.Message;
            done = true;
        }
     });

   //A loop to check done if ajax call is done.
   while (!done)
   {
      setTimeout(function(){ },500); // take a sleep.
   }

    return label;
}
 -4
Author: ChinaHelloWorld,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-27 23:32:28