web-dev-qa-db-fra.com

Comment faire en sorte que cette boucle asynchrone foreach fonctionne avec des promesses?

Je me suis déjà amusé avec les promesses, mais je les connais pour la première fois et je n'arrive pas à comprendre comment le faire correctement. Pour le moment, la promesse n'a aucun sens, car elle n'attend pas que le $.get asynchrone se termine.

En gros, chaque itération foreach a sa propre fonction $.get et je dois toutes les terminer, puis passer à la partie qui contient le "... gets albumart" console.log.

$.get(id,function(data) {
    //(there's some code here)
    var getZippyUrls = new Promise(function(resolve) {
            zippyarray.forEach(function(zippy) {
            //(more code)
            $.get(zippy.full, function(data) {
                //^This is the foreach of $.gets
               //(code's here)
            });  
           resolve(zippyarray);
        });
    });

    //This is my failed Promise ->
    getZippyUrls.then(function(response) {
        console.log("WE'RE OUT " + response.length);
        response.foreach(function(d) {
            console.log("Promise"+d.media);
        });
        console.log('eyyyyyy');
    });

    console.log("...gets albumart");
    //Now after the previous stuff is done, move on
15
Fabis

En code synchrone, la continuation est effectuée à la fin de la ligne ; 

Avec les promesses, la continuation est effectuée via .then. Vous utilisiez un constructeur de promesse et le résolviez immédiatement, vous n’attendiez aucune tâche. Je mappais mon travail en tâches et je les enchaînais ensuite ou les attendais en série.

//I'm assuming
zippyarray; // array of Zippy objects

var tasks = zippyarray.map(function(zippy,i){
    return function(){ // return a task on that zippy;
       // basic logic here
       return $.get({
            // ajax request
       }).then(function(data){
            // process data like in your code
            // possibly store later for later use too
            return process(data); // return the processed data;
       });
    }
});

Maintenant nous pouvons tous les exécuter séquentiellement:

 var p = tasks[0](); // start the first one
 for(var i = 1; i < tasks.length; i++) p = p.then(tasks[i]);
 p.then(function(result){
       // all available here
 });

Ou mieux, en série:

$.when.apply(tasks.forEach(function(t){ return t(); })).then(function(results){
     // all done
})
20
Benjamin Gruenbaum

Je sais que c'est une vieille question, mais les choses ont un peu changé récemment.

Si vous êtes prêt à utiliser des bibliothèques externes, la bibliothèque Bluebird promise est très bien implémentée: Promise.each .

Par exemple.

function helperFunc(zippyarray) {
  return Promise.each(zippyarray, zippy => {
    return someOperationThatReturnAPromise(zippy)
      .then((singleResult) => {
        // do something with the operation result if needed
      })
  }).then((originalArray) => {
    // this happens only after the whole array is processed
    // (result is the original array here)
    return Promise.resolve(originalArray)
  })
}
10
MJV

Pour garder trace de plusieurs requêtes get que vous utilisez de cette façon:

var cnt = requestCnt;

function finished(){
    if(--cnt)return;
    // Your code here
}

for(var i = 0; i < requestCnt; ++i){
    $.get('something.htm', {data:data}, function(data){
        finished();
    });
}

Vous appelez toujours la fonction terminée lorsqu'une demande obtient une réponse. La fonction finie fait le travail quand tout est fini.

0
Fuzzyma

Aujourd'hui, si j'avais besoin de le faire de manière séquentielle, je le ferais avec async/await:

//I'm assuming I'm inside an `async` function
zippyarray; // array of Zippy objects

for(const task of zippyArray) {
  const result = await $.get({ ... });
  // do stuff with result
}
0
Benjamin Gruenbaum