Prima ES2017 e async/await
(vedi sotto per un'opzione in ES2017), non è possibile utilizzare .forEach()
se si desidera attendere una promessa, perché le promesse non stanno bloccando Javascript e promesse semplicemente non funzionano in questo modo.
È possibile concatenare più promesse e fare in modo che l'infrastruttura promessa le segua.
È possibile scorrere manualmente e avanzare l'iterazione solo al termine della promessa precedente.
È possibile utilizzare una libreria come async
o Bluebird
che li eseguirà in sequenza.
Ci sono molte alternative diverse, ma lo .forEach()
non lo farà per voi.
Ecco un esempio di sequenziamento usando concatenazioni di promesse con promesse angolari (supponendo objects
è un array):
objects.reduce(function(p, val) {
return p.then(function() {
return doSomething(val);
});
}, $q.when(true)).then(function(finalResult) {
// done here
}, function(err) {
// error here
});
E, usando promesse ES6 standard, questo sarebbe:
objects.reduce(function(p, val) {
return p.then(function() {
return doSomething(val);
});
}, Promise.resolve()).then(function(finalResult) {
// done here
}, function(err) {
// error here
});
Ecco un esempio di sequenziamento manuale (supponendo che objects
sia un array), t hough questo non riferire il completamento o errori come l'opzione di cui sopra fa:
function run(objects) {
var cntr = 0;
function next() {
if (cntr < objects.length) {
doSomething(objects[cntr++]).then(next);
}
}
next();
}
ES2017
Nel ES2017, la funzione async/wait
fa permettono di "aspettare" per una promessa di adempiere prima di continuare l'iterazione del ciclo quando si utilizza loop non basati funzione come for
o while
:
async function someFunc() {
for (object of objects) {
// wait for this to resolve and after that move to next object
let result = await doSomething(object);
}
}
Il codice deve essere contenuto all'interno di una funzione async
e quindi è possibile utilizzare await
per dire all'interprete di attendere la promessa da risolvere prima di continuare il ciclo. Nota, mentre questo sembra essere un comportamento di tipo "bloccante", non sta bloccando il ciclo degli eventi. Altri eventi nel ciclo degli eventi possono ancora essere elaborati durante lo await
.
La tua soluzione "reduce" è elegante, ma non funziona. '$ q.defer(). resolve()' risolve una promessa, ma restituisce undefined, quindi 'p' non è definito per il primo elemento. – AgDude
@AgDude - Se sai cosa suggerire, ti preghiamo di proporre una modifica alla mia risposta. Non tengo il passo con tutte le diverse librerie di promesse proprietarie (quando c'è uno standard ES6 per tutto questo ora) quindi se questo non è il modo corretto di creare una promessa risolta per iniziare la catena, allora non sono – jfriend00
soluzione elegante e pulita – refactor