Attendre que toutes les requêtes Jquery Ajax soient terminées?

Comment faire pour qu'une fonction attende jusqu'à ce que toutes les requêtes Ajax jQuery soient faites à l'intérieur d'une autre fonction?

bref, je dois attendre que toutes les requêtes Ajax soient faites avant d'exécuter la prochaine. Mais comment?

577
demandé sur Maistrenko Vitalii 2010-09-14 18:02:45

19 réponses

jQuery définit maintenant une lorsque la fonction à cette fin.

il accepte n'importe quel nombre D'objets différés comme arguments, et exécute une fonction quand chacun d'eux résoudre.

cela signifie que, si vous voulez lancer (par exemple) quatre requêtes ajax, puis effectuer une action quand elles sont faites, vous pouvez faire quelque chose comme ceci:

$.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,            
        ...
    });
}

à mon avis, il fait pour une syntaxe propre et claire, et évite d'impliquer toutes les variables globales comme ajaxStart et ajaxStop, qui pourraient avoir des effets secondaires indésirables que votre page se développe.

si vous ne savez pas à l'avance combien d'arguments ajax vous devez attendre (i.e. vous voulez utiliser un nombre variable d'arguments), il peut encore être fait mais est juste un peu plus compliqué. Voir passer dans un tableau de Deferreds à $.quand () (et peut-être jQuery .lors du dépannage avec un nombre variable de arguments ).

si vous avez besoin de plus de contrôle sur les modes de défaillance des scripts ajax, etc., vous pouvez sauvegarder l'objet retourné par .when() - c'est un jQuery promesse objet englobant toutes les requêtes ajax originales. Vous pouvez appeler .then() ou .fail() pour ajouter des gestionnaires de succès/Échecs détaillés.

782
répondu Alex 2018-04-13 10:32:12

si vous voulez attendre jusqu'à ce que toutes les requêtes ajax soient terminées dans votre document, peu importe combien d'entre elles existent, il suffit d'utiliser $.ajaxStop événement de cette façon:

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

dans ce cas, il n'est pas nécessaire de deviner combien de requêtes peuvent être dans une application qui pourrait finir dans le futur. Dans certains cas, les requêtes ajax peuvent faire partie de la logique interne d'une fonction, ce qui peut être assez compliqué (par exemple appeler d'autres fonctions), et dans ce cas, cas, vous ne pouvez pas attendre jusqu'à ce que ladite fonction est fait avec sa logique entière plutôt que seulement en attendant la partie ajax à compléter.

$.ajaxStop ici peut aussi être lié à n'importe quel noeud HTML que vous pensez pourrait être modifié par ajax .

encore une fois le but de ce handler est de savoir quand il n'y a pas actif ajax ne pas effacer ou réinitialiser quelque chose.

P.S. si cela ne vous dérange pas d'utiliser la syntaxe ES6, alors vous pouvez utiliser Promise.all pour les méthodes connues ajax . Exemple:

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

un point intéressant est qu'il fonctionne à la fois avec les requêtes Promises et $.ajax . Voici jsFiddle démontrant le dernier.

258
répondu Arsen Khachaturyan 2018-07-02 10:05:38

j'ai trouvé un bonne réponse par gnarf mon moi qui est exactement ce que je cherchais:)

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

alors vous pouvez ajouter une requête ajax à la file d'attente comme ceci:

$.ajaxQueue({
        url: 'page.php',
        data: {id: 1},
        type: 'POST',
        success: function(data) {
            $('#status').html(data);
        }
    });
30
répondu jamietelin 2017-05-23 12:34:54

NOTE: les réponses ci-dessus utilisent des fonctionnalités qui n'existaient pas au moment où cette réponse a été écrite. Je recommande d'utiliser jQuery.when() au lieu de ces approches, mais je laisse la réponse à des fins historiques.

-

vous pourriez probablement vous en sortir avec un simple sémaphore de comptage, bien que la façon dont vous l'implémentez dépende de votre code. Un exemple simple serait quelque chose comme...

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;

si vous vouliez que cela fonctionne comme {async: false} mais que vous ne vouliez pas verrouiller le navigateur, vous pourriez accomplir la même chose avec une file d'attente 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
répondu BBonifield 2016-07-20 22:15:02

utilisez l'événement ajaxStop .

par exemple, disons que vous avez un chargement ... message tout en récupérant 100 requêtes ajax et vous voulez cacher ce message Une fois chargé.

du jQuery doc :

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

notez Qu'il attendra que toutes les requêtes ajax soient faites sur cette page.

19
répondu olafure 2016-02-05 18:34:49

un petit contournement est quelque chose comme ceci:

// 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();
});

l'Espoir peut être utile...

7
répondu Jesfre 2012-10-26 16:13:01

javascript est basé sur les événements, donc vous ne devriez jamais wait , plutôt définir hooks /callbacks

vous pouvez probablement juste utiliser les méthodes réussies/complètes de jquery.ajax

ou vous pouvez utiliser .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...
  }
});

bien que vous devriez poster un pseudo de la façon dont votre(s) requête(s) ajax est(sont) appelée (s) pour être plus précise...

6
répondu Stefano 2010-09-14 15:07:02

jQuery vous permet de spécifier si vous voulez que la requête ajax soit asynchrone ou non. Vous pouvez simplement rendre les requêtes ajax synchrones et le reste du code ne sera pas exécuté tant qu'elles ne seront pas retournées.

par exemple:

jQuery.ajax({ 
    async: false,
    //code
});
2
répondu shmuel613 2016-12-21 09:01:17

vous pouvez aussi utiliser async.js .

je pense que c'est mieux que $.quand parce que vous pouvez fusionner toutes sortes d'appels asynchrones qui ne prennent pas en charge les promesses comme les timeouts, les appels SqlLite, etc. et pas seulement des requêtes ajax.

1
répondu George Mavritsakis 2016-02-04 18:32:03

sur la base de la réponse @BBonifield, j'ai écrit une fonction utilitaire pour que la logique sémaphore ne soit pas répandue dans tous les appels ajax.

untilAjax est la fonction utilitaire qui invoque une fonction de rappel lorsque tous les appels AJAX sont terminés.

ajaxObjs est un tableau d'objets ajax [http://api.jquery.com/jQuery.ajax/] .

fn est fonction de rappel

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

exemple: doSomething la fonction utilise 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
répondu Sanjeev Kumar Dangi 2016-02-05 19:05:25

je recommande fortement d'utiliser $.quand () si vous partez de zéro.

même si cette question a plus de millions de réponses, je n'ai toujours rien trouvé d'utile pour mon cas. Disons que vous avez affaire à un codebase existant, déjà faire quelques appels ajax et ne veulent pas introduire la complexité des promesses et/ou de refaire le tout.

nous pouvons facilement profiter de jQuery .data , .on et .trigger fonctions qui ont fait partie de jQuery depuis toujours.

Codepen

Les bonnes choses au sujet de ma solution est la suivante:

  • il est évident ce que le rappel dépend exactement de

  • la fonction triggerNowOrOnLoaded ne se soucie pas si les données ont déjà été chargées ou nous sommes toujours en attente pour elle

  • c'est super facile de le brancher dans un code existant

$(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
répondu cilf 2017-08-28 11:15:42

$.when ne fonctionne pas pour moi, callback(x) au lieu de return x a travaillé comme décrit ici: https://stackoverflow.com/a/13455253/10357604

1
répondu thestruggleisreal 2018-10-05 10:48:44

Si vous avez besoin de quelque chose de simple; une fois et fait de rappel

        //multiple ajax calls above
        var callback = function () {
            if ($.active !== 0) {
                setTimeout(callback, '500');
                return;
            }
            //whatever you need to do here
            //...
        };
        callback();
0
répondu Fatmuemoo 2013-05-21 14:12:03

j'ai rencontré ce problème et créé un plugin Générique jquery_counter pour le résoudre: https://bitbucket.org/stxnext/jquery_counter/

0
répondu zefciu 2013-12-15 16:10:30

j'ai trouvé moyen simple, il en utilisant 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
répondu uingtea 2016-01-12 15:39:09

ma solution est la suivante

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

a bien fonctionné. J'ai essayé beaucoup de différentes façons de le faire, mais j'ai trouvé que c'était la plus simple et la plus réutilisable. Espérons que cela aide

0
répondu Eric Sean Moore 2016-02-05 18:34:00

regardez ma solution:

1.Insérez cette fonction (et variable) dans votre fichier 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.Construisez un tableau avec vos requêtes, comme ceci:

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.Créer la fonction de rappel:

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

4.Appelez la fonction runFunctionQueue avec les paramètres:

runFunctionQueue(f, 0, QuestionInsert_callback);
// first parameter: array with requests data
// second parameter: start from first request
// third parameter: the callback function
0
répondu Briganti 2016-02-05 18:54:44

Solution donnée par Alex fonctionne très bien. Même concept mais en l'utilisant, une manière un peu différente (lorsque le nombre d'appels n'est pas connu à l'avance)

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

-1
répondu athap 2014-03-09 02:45:37

Essayez par ici. faites une boucle à l'intérieur de la fonction java script pour attendre que l'appel ajax soit terminé.

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
répondu ChinaHelloWorld 2014-02-27 23:32:28