Question Attendez que toutes les requêtes jQuery Ajax soient terminées?


Comment est-ce que je fais une fonction attendez jusqu'à ce que toutes les demandes de jQuery Ajax soient faites dans une autre fonction?

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


562
2017-09-14 14:02


origine


Réponses:


jQuery définit maintenant un quand la fonction dans ce but.

Il accepte n'importe quel nombre d'objets différés en tant qu'arguments et exécute une fonction lorsque tous les résolvent.

Cela signifie que si vous voulez initier (par exemple) quatre requêtes ajax, alors effectuez une action quand elles sont faites, vous pourriez 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, cela permet une syntaxe claire et claire, et évite d'impliquer des variables globales telles que ajaxStart et ajaxStop, qui pourraient avoir des effets secondaires indésirables au fur et à mesure que votre page se développe.

Si vous ne savez pas à l'avance combien d'arguments ajax vous devez attendre (c'est-à-dire si vous voulez utiliser un nombre variable d'arguments), cela peut encore être fait mais c'est un peu plus compliqué. Voir Transmettez un tableau de différés à $ .when () (et peut-être jQuery .when dépannage avec un nombre variable d'arguments).

Si vous avez besoin d'un contrôle plus approfondi sur les modes de défaillance des scripts ajax etc., vous pouvez enregistrer l'objet retourné par .when() - C'est un jQuery Promettre objet englobant toutes les requêtes ajax d'origine. Tu peux appeler .then() ou .fail() dessus pour ajouter des gestionnaires de succès / échec détaillés.


761
2018-03-25 23:54



Si vous voulez attendre que toutes les requêtes ajax soient terminées dans votre document, peu importe leur nombre, utilisez simplement $.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 demandes peuvent être dans une application qui pourrait se terminer 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, vous ne pouvez pas attendre que cette fonction soit entièrement logique. seulement attendant le ajax partie à compléter.

$.ajaxStop ici peut également être lié à tout HTML nœud que vous pensez pourrait être modifié par ajax.

Encore une fois le but de ce gestionnaire 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 connu ajax méthodes Exemple:

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

Un point intéressant ici est que cela fonctionne à la fois avec Promises et $.ajax demandes Voici jsFiddle démontrer le dernier.


254
2017-12-26 08:42



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

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

29
2017-09-14 15:26



REMARQUE: 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 débrouiller 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 faire 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
2017-09-14 14:26



Utilisez le ajaxStop un événement.

Par exemple, disons que vous avez un chargement ... message lors de l'extraction de 100 requêtes ajax et vous souhaitez masquer ce message une fois chargé.

De la jQuery doc:

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

Notez qu'il attendra que toutes les requêtes ajax soient effectuées sur cette page.


19
2018-05-24 11:42



Une petite solution de 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
2017-09-14 15:07



javascript est basé sur les événements, donc vous ne devriez jamais attendez, plutôt définir des crochets / rappels

Vous pouvez probablement utiliser les méthodes de succès / complètes de jquery.ajax

Ou vous pourriez 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 afficher un pseudo-code de la façon dont votre (vos) requête (s) ajax est (sont) appelée (s) pour être plus précise ...


6
2017-09-14 14:27



jQuery vous permet de spécifier si vous souhaitez que la requête ajax soit asynchrone ou non. Vous pouvez simplement rendre les requêtes ajax synchrones, puis le reste du code ne s'exécutera pas jusqu'à leur retour.

Par exemple:

jQuery.ajax({ 
    async: false,
    //code
});

2
2018-02-19 15:33



Sur la base de la réponse de @BBonifield, j'ai écrit une fonction d'utilité pour que la logique des sémaphores ne soit pas répartie dans tous les appels ajax.

untilAjax est la fonction d'utilité qui appelle une fonction de rappel lorsque tous les ajaxCalls sont terminés.

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

fn est la 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 utilisations de la fonction 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
2017-08-28 11:15



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

Même si cette question a plus d'un million de réponses, je n'ai toujours rien trouvé d'utile pour mon cas. Disons que vous devez faire face à une base de code existante, en faisant déjà quelques appels ajax et ne voulez pas introduire la complexité des promesses et / ou refaire le tout.

Nous pouvons facilement profiter de jQuery .data, .on et .trigger fonctions qui font partie de jQuery depuis toujours.

Codepen

Les bonnes choses à propos de ma solution sont:

  • il est évident 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 l'attendons toujours

  • 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
2018-05-21 14:03