2015-02-23 13 views
16

Ho una funzione da una libreria che restituisce una promessa. Ho bisogno di eseguire questa funzione più volte, ma ogni iterazione deve attendere fino al completamento dell'attività precedente.Come si risolve in modo sincrono una catena di promesse es6?

La mia ipotesi è che ho potuto fare questo:

promiseReturner(1) 
    .then(promiseReturner(2) 
    .then(promiseReturner(3) 
    .then(...) 

Quale potrebbe essere semplificata utilizzando un ciclo:

var p = Promise.resolve(); 
for (var i=1; i<=10; i++) { 
    p = p.then(promiseReturner(i)); 
} 

Tuttavia, quando faccio questo ogni promessa della catena viene eseguito al Allo stesso tempo, invece di uno dopo l'altro come .then() sembra implicare. Chiaramente mi manca qualcosa di fondamentale sulle promesse - ma dopo aver letto diversi tutorial e post sul blog sono ancora perso.

Here's a codepen I wrote up to demonstrate my attempt.

+1

Does 'promiseReturner (n) 'restituire una promessa o effettuare una funzione di ritorno della promessa? – Bergi

risposta

21

La soluzione "non loop" non dovrebbe funzionare neanche. Devi passare una funzione -.then, non una promessa:

var p = Promise.resolve(); 
for (var i=1; i<=10; i++) { 
    (function(i) { 
     p = p.then(function() { 
      return promiseReturner(i); 
     }); 
    }(i)); 
} 

Se quella funzione restituisce una promessa, quindi si ottiene quell'effetto concatenamento.

Ulteriori informazioni sulle promesse su MDN.


può essere semplificato con (funzioni e freccia) let:

var p = Promise.resolve(); 
for (let i=1; i<=10; i++) { 
    p = p.then(() => promiseReturner(i)); 
} 

O .bind (che è ES5):

var p = Promise.resolve(); 
for (var i=1; i<=10; i++) { 
    p = p.then(promiseReturner.bind(null, i)); 
} 
+2

Forse più chiaro: "devi passare una funzione * restituendo una promessa *"? –

+0

non importa che tu spieghi che più avanti su –

+0

avevo provato a metterlo in una funzione precedente [vedi qui] (http://codepen.io/anon/pen/zxjExL?editors=001), ma sembrava funzionare solo l'ultima promettere.Perché il wrapping che lo blocca in una funzione autoinvitante sembra risolverlo? –

1

È possibile utilizzare async/await utilizzando generatori ES6 e una biblioteca come co.

co(function*() { 
    while(upto < 10) { 
    var result = yield Promise.resolve(true); 
    } 
    return result; 
}).then(function (value) { 
    console.log(value); 
}, function (err) { 
    console.error(err.stack); 
}); 

Ecco qualche dettaglio come funziona: http://davidwalsh.name/async-generators

1

Ecco una soluzione che ho usato per risolvere lo stesso problema:

var recursiveFunction = function(values) { 
    return new Promise(function(resolve, reject) { 
    if (values.length <= 0) { 
     return resolve(); 
    } else { 
     return promiseReturner(values[0]).then(function() { 
      values.shift(); 
      return recursiveFunction(values).then(function() { 
       resolve(); 
      }); 
     }); 
     } 
    }); 
} 

recursiveFunction([1,2]).then(function(r) { 
console.warn('Finished solving promises sequentially'); 
}) 
0

Se si utilizza ES6, è possibile raggiungere questo obiettivo usando array.reduce . Penso abbastanza bene.

const functions = [/* array of functions which return promises */]; 
const finalPromise = functions.reduce(async (promise, asyncFn) => { 
    await promise; 
    return asyncFn(); 
}, Promise.resolve()); 
-1

È possibile eseguire il codice tramite nsynjs, per mettere in pausa l'esecuzione su ogni funzione che restituisce promessa, e aspetterà fino promessa viene risolto:

var promiseReturner = function(i) { 
 
    return new Promise(function(resolve, reject) { 
 
     setTimeout(function(){ 
 
      resolve("result is "+i) 
 
     }, 1000); 
 
    }); 
 
}; 
 

 
function synchronousCode() { 
 
    for (var i=1; i<=10; i++) { 
 
     var p=promiseReturner(i); // nsynjs will pause here until promise is resolved 
 
     console.log(p.data); // `data` will contain result of the promise 
 
    } 
 
}; 
 
\t 
 
nsynjs.run(synchronousCode, null, function(){ 
 
\t console.log("finish"); 
 
});
<script src="https://rawgit.com/amaksr/nsynjs/master/nsynjs.js"></script>

Problemi correlati