2017-08-14 4 views
0

J'ai actuellement un code jQuery qui ressemble un peu à ceci:Enumérer les appels synchrones ajax avec des promesses

for (i = 0; i < limitVar; i++) { 
doAjaxStuff(i); 
} 

function doAjaxStuff(i) { 
Here we make a SYNCHRONOUS ajax call, sending i. 
} 

L'appel ajax doit être synchrone - on ne se déclenche pas jusqu'à ce que le dernier est fait. Comme le JS synchrone est déprécié, je veux déplacer ce code pour utiliser des promesses. Comment pourrais-je y parvenir? J'ai été incapable de trouver un exemple assez proche de cette situation.

+0

@KevinB Promise.all() on tire toutes les demandes à la fois. Si la taille d'un tableau est assez grande, cela va sûrement épuiser les ressources, ce qui entraînera des demandes défaillantes. – cepharum

+0

Vous pouvez utiliser [] .reduce pour créer une chaîne qui les appelle l'une après l'autre. Voici par exemple: https://stackoverflow.com/questions/21372320/how-to-chain-execution-of-array-of-functions-when-every-function-returns-deferre –

+0

Passer aux promesses signifie passer à asynchrone. – Bergi

Répondre

0

Vous ne faites pas synchrone ajax dans le navigateur (bien sur le plan technique, vous pouvez, dans certaines circonstances, mais il est vraiment une mauvaise idée de le faire, car il bloque le navigateur lors de l'appel ajax). Au lieu de cela, vous remodelez votre boucle de sorte qu'elle n'effectue que l'appel ajax suivant lorsque le précédent est terminé, ce qui signifie que vous devez effectuer une boucle manuellement, vous ne pouvez pas utiliser une boucle for. Puisque votre code est pseudo-code (vous n'affichez pas l'opération réelle ajax), j'utiliserai un exemple jQuery ajax, mais vous pouvez remplacer n'importe quelle fonction ajax tant qu'elle renvoie une promesse ou utilise un rappel pour signaler quand c'est fait.

L'idée générale est que vous créez une fonction pour votre appel ajax et que vous utilisez le rappel de fin pour incrémenter votre index, puis exécuter l'itération suivante de votre boucle.

function runLoop(data) { 
    var i = 0; 

    function next() { 
     if (i < data.length) { 
      return $.ajax(data[i]).then(function(data) { 
       ++i; 
       return next(); 
      }); 
     else { 
      // all done with loop 
     } 
    } 
    return next(); 
} 

// call it like this 
runLoop(someArray).then(function() { 
    // all done here 
}); 

Si vous ne disposez pas d'un tableau de données, mais je veux juste un indice de boucle:

function runLoop(limitVar) { 
    var i = 0; 

    function next() { 
     if (i < limitVar) { 
      return $.ajax(something_with_i_in_it).then(function(data) { 
       ++i; 
       return next(); 
      }); 
     else { 
      // all done with loop 
     } 
    } 
    return next(); 
} 

// call it like this 
runLoop(theLimit).then(function() { 
    // all done here 
}); 

Si votre limitVar n'est pas grand et il n'y a pas d'autre logique qui pour décider de poursuivre ou non la boucle, vous pouvez également utiliser un peu plus simple modèle si vous avez une fonction ajax qui renvoie une promesse:

function runLoop(limitVar) { 
    var p = Promise.resolve(); 
    for (var i = 0; i < limitVar; i++) { 
     p = p.then(function(prevResult) { 
      return someAjax(i); 
     }); 
    } 
    return p; 
} 

// call it like this 
runLoop(theLimit).then(function() { 
    // all done here 
}); 

Si vous n'utilisez les fonctions ajax qui renvoient une promesse, il est seulement quelques lignes de code pour envelopper votre fonction avec celle qui le fait et vous pouvez ensuite utiliser plus facilement ces modèles de conception.

+0

Pourquoi la downvote? Quel est le problème avec cette réponse? Les utilisateurs ne peuvent améliorer leurs réponses que pour répondre à une objection négative si vous fournissez des commentaires sur les raisons pour lesquelles ils sont refusés. – jfriend00

0

Traite le tableau en utilisant une fonction séparée. Chaque fois que vous enlevez un autre élément de tableau, puis le traiter et quand c'est fait, appelez la fonction à nouveau. S'il n'y a plus d'élément dans la liste, tout le processus est terminé.

 
var listOfRequests = ...; 

new Promise(function(resolve, reject) { 
    requestNext(); 

    function requestNext() { 
     if (!listOfRequests.length) { 
      return resolve(); 
     } 

     var next = listOfRequests.shift(); 

     doAjaxStuff(next, reject, requestNext); 
    } 
}) 

doAjaxStuff(request, errCallback, doneCallback) { 
    ... 
} 
-1

c'est un modèle assez simple:

var queue = Promise.resolve(); 
var nop =() => null; 

for(let i=0; i<limitVar; ++i){ 
    queue = queue.then(() => doAjaxStuff(i)); 
    //or if you want to ignore Errors 
    //queue = queue.then(() => doAjaxStuff(i)).catch(nop); 
} 

queue.then(() => console.log("finished")); 

Ou si vous utilisez un tableau en entrée:

var done = data.reduce(
    (queue, value, index) => queue.then(() => doSomethingWith(value, index)), 
    Promise.resolve() 
); 

done.then(() => console.log("finished"));