2017-10-03 6 views
1

J'ai un problème pour faire des retards entre les requêtes ajax en boucle. Je veux que le script attende 7 secondes pour faire le suivant. Les demandes ne sont pas identiques, et je ne sais pas combien d'entre elles peuvent l'être. Retarder jQuery Ajax dans la boucle For

$(document).ready(function() { 
    var announce = $("#announce").data('id'); 
    var lots_cnt = parseInt($("#announce").data('lotscnt')); 
    for (var i = 0; i < Math.ceil(lots_cnt/20); i++) { 
     $.ajax({ 
       method: "GET", 
       url: "/project/lots/"+announce+"/"+(i+1), 
       async: false, 
       beforeSend: function() { 
        $("#console").append("<strong>Parsing lots from page "+(i+1)+"...</strong><br/>"); 
       }, 
       complete:function(){ 

       }, 
       success: function (m) { 
        $("#console").append(m); 
        addprogressstep(); 
        setTimeout(function() { $("#console").append("Waiting 7 sec ...<br/>"); }, 7000); 
       }, 
       error:function(jqXHR, textStatus, errorThrown){ 

       } 
      }); 
    }; 

}); 
+0

['setTimeout()'] (https://developer.mozilla.org/ro/docs/Web/API/window.setTimeout). Cela dit, envoyer autant de requêtes AJAX n'est pas une bonne idée si cela peut être évité. Je suggère de regarder dans l'envoi de toutes les données dans une seule demande, si possible. Cependant, vous devriez *** supprimer définitivement 'async: false' car c'est une pratique horrible - si vous vérifiez la console, vous verrez même le navigateur vous dire de ne pas l'utiliser. –

+0

Ce n'est pas beaucoup de demandes comme il ressemble, c'est entre 1 à 6, donc je pense que les navigateurs et le réseau sont bons avec ça. Malheureusement, je ne peux pas faire une requête à la place de cette boucle, et j'ai besoin de ce délai pour éviter l'erreur "429 Too Many Requests". –

+0

Les navigateurs ne posent pas de problème, mais votre serveur/société d'hébergement peut ne pas l'être si vous avez envoyé N N * utilisateurs par minute au serveur. –

Répondre

1

Ceci est une question fantastique!

Je vois que vous utilisez jQuery .ajax. Selon jQuery documentation, $.get() renvoie maintenant une promesse. Nous pouvons utiliser des promesses pour réaliser ce que vous voulez.

Tout d'abord, dans votre boucle for, for (var i = 0; i < Math.ceil(lots_cnt/20); i++) {, la première chose à faire est de lancer $.ajax. Au lieu de cela, ce que nous allons faire est construire un tableau de fonctions, où chaque fonction renvoie une promesse.

var funcArray = []; 
// EDIT changed var i to let i 
for (let i = 0; i < Math.ceil(lots_cnt/20); i++) { 
    var getFunction = function(){ 
     var getPromise = $.get(...); 
     return getPromise; 
    } 
    funcArray.push(getFunction); 
} 

Ensuite, vous allez écrire une fonction récursive (ish) pour traiter chaque fonction, lorsque le précédent se termine (et après un délai d'attente si vous le souhaitez)

function runNext(){ 
    if (funcArray.length > 0) { 
     var nextFunction = funcArray.shift(); 
     nextFunction() // this is our $.get promise 
      .then(function(resultOfGet){ 
       // do something with your result 
       setTimeout(runNext,1000*7); 
      }) 
    } 
} 

runNext(); 

--- modifier --- Voici comment vous pourriez transformer en $.ajax une promesse:

function ajx(i) { 
    return new Promise(function(resolve, reject){ 
     $.ajax({ 
      method: "GET", 
      url: "/project/lots/"+announce+"/"+(i+1), 
      async: false, 
      beforeSend: function() { 
       $("#console").append("<strong>Parsing lots from page "+(i+1)+"...</strong><br/>"); 
      }, 
      complete:function(){ 

      }, 
      success: function (m) { 
       $("#console").append(m); 
       addprogressstep(); 
       resolve(m); 
      }, 
      error:function(jqXHR, textStatus, errorThrown){ 
       reject(jqXHR, textStatus, errorThrown); 
      } 
     }); 
    })  
} 
+1

Merci, je n'ai pas pensé à la récursivité. Votre code n'a pas fonctionné pour moi, il essayait d'exécuter la fonction de funcArray avec i = 6 tout le temps. Donc je l'ai fait comme ça: 'var lots_cnt = parseInt ($ (" # announce "). Data ('lotscnt')); \t var pages = Math.ceil (lots_cnt/20); \t var currentPage = 1; \t fonction runNext() { \t \t .get $ ("/ goszakup/lots /" + annonce + "/" + currentPage, fonction (m) { \t \t \t $ ("# console").ajouter (m); \t \t \t addprogressstep(); \t \t \t currentPage ++; \t \t \t si (currentPage <= pages) setTimeout (runNext, 1000 * 7); \t \t}); Run0ext(); ' –

+0

Ah oui, quand vous bouclez de cette façon avec des clojures, la variable 'i' finirait toujours avec la plus grande valeur. Je n'y ai pas pensé. – TKoL

+0

@ ГлебГарипов ce bug sur la boucle 'i' pourrait être corrigé par 'let' au lieu de' var' je pense. – TKoL

0

vous pouvez fixer avec map au lieu de for.

si la carte d'utilisation, vous pouvez modifier async réglage true

Lorsque vous traitez avec le traitement asynchrone, il est préférable d'utiliser la carte plutôt que pour la déclaration.