2014-04-14 12 views
15

Ho già giocato con Promises, ma sono nuovo per loro e non riesco a capire come farlo correttamente. Al momento, non c'è motivo per la Promessa, perché non aspetta fino al completamento della versione asincrona $.get.Come posso fare in modo che questo ciclo aseach async funzioni con le promesse?

Fondamentalmente, ogni foreach iterazione ha una sua funzione $.get, e ho bisogno di avere tutti loro completo e poi proseguire fino alla parte che ha il "... ottiene 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 
+0

genere con quella gente codice molto non si preoccupano neppure leggere la tua domanda. –

+1

Madre del codice! – Arthur

+0

Non c'è bisogno di leggere tutto, la domanda di base è la stessa: c'è un ciclo foreach con $. Funzioni get, e ho bisogno che tutti completino prima di andare avanti. Accorgerò il codice, credo ... – Fabis

risposta

20

Nel codice sincrono, seguito viene eseguita quando la linea termina ;

Con promesse, continuazione avviene tramite .then. Stavi usando un costruttore di promesse e lo hai risolto immediatamente, non hai aspettato alcuna attività. Mapperei il mio lavoro in compiti e poi li incatenerei o li attenderò in serie.

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

Ora siamo in grado di eseguire tutti loro in sequenza:

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

O meglio, in serie:

$.when.apply(tasks.forEach(function(t){ return t(); })).then(function(results){ 
    // all done 
}) 
+0

Non capisco perché ci sono 3 ritorni nella funzione map(). Potresti chiarirlo? Cosa fanno ciascuno di loro? – Fabis

+0

@Fabis il ritorno esterno restituisce l'attività. Mappiamo ogni zippy ad una funzione. Il secondo ritorno è dalla funzione compito e restituisce il risultato di '$ .get' (una promessa). Il terzo ritorno serve a restituire un valore da un gestore '.then'. In generale, quando si restituisce un valore da un gestore allora risolverà la promessa con quel valore, se quel valore è una promessa essa stessa risolverà la promessa esterna con il suo valore da scartare. –

+0

Se ho usato 'return process()', ricevo l'errore: 'Rifiuto non gestito TypeError: Property 'process' dell'oggetto # non è una funzione 'Mi fa pensare che non dovrei usare la funzione process quando restituisco un matrice di oggetti –

0

per tenere traccia delle molteplici richieste GET-si utilizza in questo modo:

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

Si chiama sempre il finishe d-function quando una richiesta ottiene una risposta. La funzione finita fa il lavoro quando tutto viene fatto.

+1

Questo sta implementando manualmente la logica già esistente con le promesse. Si chiama semaforo asincrono btw. –

+0

Bello sapere il nome. Non è mai sbagliato conoscere il codice dietro la funzione. Specialmente se stai utilizzando jquery-lib sulla tua pagina – Fuzzyma

+0

Non hai bisogno della libreria jQuery, puoi usare un browser moderno (le promesse fanno parte della nuova specifica ES6), o una buona promessa libreria (come Bluebird) . Dover fare manualmente questo come il tuo codice non tiene conto di molte cose (gestione degli errori, ecc.). Potrebbe essere scritto come '$ .when.apply (requests.map (function (el) {return $ .get (" something.html ", {data: el});})). Then (function (results) {/* risultati tutti disponibili qui * /}); ' –

10

So che questa è una vecchia domanda ma le cose sono cambiate un po 'di recente.

Se stai utilizzando le librerie esterne, la libreria di promemoria Bluebird Bluebird ha un'implementazione piuttosto buona per questo: Promise.each.

E.g.

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) 
    }) 
} 
+0

Ciao, puoi dare un altro esempio senza usare bluebird? Ho solo bisogno di Promise.each. Usando bluebird ho ottenuto un grosso file compilato. Non va bene –

+0

Se non vuoi usare le librerie (forse oltre a jQuery che è usato nella domanda stessa), penso che la risposta di Benjamin potrebbe essere la strada da percorrere. Oppure, se stai usando ES6, puoi aggiungere tutte le chiamate di funzione desiderate in una raccolta e quindi usare 'Promise.all' con quello. – MJV

0

Oggi se avevo bisogno di farlo in modo sequenziale - lo farei con 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 
} 
Problemi correlati