Tengo un bucle que llama a un método que hace cosas de forma asincrónica. Este bucle puede llamar al método muchas veces. Después de este bucle, tengo otro bucle que debe ejecutarse solo cuando se hacen todas las cosas asincrónicas.
Entonces esto ilustra lo que quiero:
for (i = 0; i < 5; i++) {
doSomeAsyncStuff();
}
for (i = 0; i < 5; i++) {
doSomeStuffOnlyWhenTheAsyncStuffIsFinish();
}
No estoy muy familiarizado con las promesas, entonces, ¿alguien podría ayudarme a lograrlo?
Así es como se doSomeAsyncStuff()
comporta mi :
function doSomeAsyncStuff() {
var editor = generateCKEditor();
editor.on('instanceReady', function(evt) {
doSomeStuff();
// There should be the resolve() of the promises I think.
})
}
Tal vez tenga que hacer algo como esto:
function doSomeAsyncStuff() {
var editor = generateCKEditor();
return new Promise(function(resolve,refuse) {
editor.on('instanceReady', function(evt) {
doSomeStuff();
resolve(true);
});
});
}
Pero no estoy seguro de la sintaxis.
s
al final dePromise
.Respuestas:
Puede usar
Promise.all
( spec , MDN ) para eso: acepta un montón de promesas individuales y le devuelve una única promesa que se resuelve cuando se resuelven todas las que le dio, o se rechaza cuando se rechaza alguna de ellas.Entonces, si hace
doSomeAsyncStuff
una promesa de devolución, entonces:const promises = []; // ^^^^^−−−−−−−−−−−−−−−−−−−−−−−−−−− use `const` or `let`, not `var` for (let i = 0; i < 5; i++) { // ^^^−−−−−−−−−−−−−−−−−−−−−−−− added missing declaration promises.push(doSomeAsyncStuff()); } Promise.all(promises) .then(() => { for (let i = 0; i < 5; i++) { // ^^^−−−−−−−−−−−−−−−− added missing declaration doSomeStuffOnlyWhenTheAsyncStuffIsFinish(); } }) .catch((e) => { // handle errors here });
MDN tiene un artículo sobre promesas aquí . También cubro las promesas en detalle en el Capítulo 8 de mi libro JavaScript: The New Toys , enlaces en mi perfil si estás interesado.
He aquí un ejemplo:
function doSomethingAsync(value) { return new Promise((resolve) => { setTimeout(() => { console.log("Resolving " + value); resolve(value); }, Math.floor(Math.random() * 1000)); }); } function test() { const promises = []; for (let i = 0; i < 5; ++i) { promises.push(doSomethingAsync(i)); } Promise.all(promises) .then((results) => { console.log("All done", results); }) .catch((e) => { // Handle errors here }); } test();
Salida de muestra (debido a que
Math.random
, lo que termina primero puede variar):fuente
Math.floor(Math.random() * 1000)
a(i * 1000)
await
está permitido. Por el momento, el único lugar que puede usarawait
es dentro de unaasync
función. (En algún momento, también podrá usarlo en el nivel superior de módulos).Una función reutilizable funciona muy bien para este patrón:
function awaitAll(count, asyncFn) { const promises = []; for (i = 0; i < count; ++i) { promises.push(asyncFn()); } return Promise.all(promises); }
Ejemplo de OP:
awaitAll(5, doSomeAsyncStuff) .then(results => console.log('doSomeStuffOnlyWhenTheAsyncStuffIsFinished', results)) .catch(e => console.error(e));
Un patrón relacionado es iterar sobre una matriz y realizar una operación asíncrona en cada elemento:
function awaitAll(list, asyncFn) { const promises = []; list.forEach(x => { promises.push(asyncFn(x)); }); return Promise.all(promises); }
Ejemplo:
const books = [{ id: 1, name: 'foo' }, { id: 2, name: 'bar' }]; function doSomeAsyncStuffWith(book) { return Promise.resolve(book.name); } awaitAll(books, doSomeAsyncStuffWith) .then(results => console.log('doSomeStuffOnlyWhenTheAsyncStuffIsFinished', results)) .catch(e => console.error(e));
fuente
const doSomeAsyncStuff = async (funcs) => { const allPromises = funcs.map(func => func()); return await Promise.all(allPromises); } doSomeAsyncStuff([ () => new Promise(resolve => setTimeout(() => resolve(), 100)), () => new Promise(resolve => setTimeout(() => resolve(), 100)), () => new Promise(resolve => setTimeout(() => resolve(), 100)), () => new Promise(resolve => setTimeout(() => resolve(), 100)), () => new Promise(resolve => setTimeout(() => resolve(), 100)), ]);
fuente
Aquí hay un código que escribí para mí mismo para comprender las respuestas que se indican aquí. Tengo consultas de mangosta en un bucle for, así que puse aquí el
asyncFunction
para que ocupe su lugar. Espero que ayude a alguien. Puede ejecutar este script en el nodo o en cualquiera de los muchos tiempos de ejecución de Javascript.let asyncFunction = function(value, callback) { setTimeout(function(){console.log(value); callback();}, 1000); } // a sample function run without promises asyncFunction(10, function() { console.log("I'm back 10"); } ); //here we use promises let promisesArray = []; let p = new Promise(function(resolve) { asyncFunction(20, function() { console.log("I'm back 20"); resolve(20); } ); }); promisesArray.push(p); for(let i = 30; i < 80; i += 10) { let p = new Promise(function(resolve) { asyncFunction(i, function() { console.log("I'm back " + i); resolve(i); } ); }); promisesArray.push(p); } // We use Promise.all to execute code after all promises are done. Promise.all(promisesArray).then( function() { console.log("all promises resolved!"); } )
fuente
/*** Worst way ***/ for(i=0;i<10000;i++){ let data = await axios.get( "https://yourwebsite.com/get_my_data/" ) //do the statements and operations //that are dependant on data } //Your final statements and operations //That will be performed when the loop ends //=> this approach will perform very slow as all the api call // will happen in series /*** One of the Best way ***/ const yourAsyncFunction = async (anyParams) => { let data = await axios.get( "https://yourwebsite.com/get_my_data/" ) //all you statements and operations here //that are dependant on data } var promises = [] for(i=0;i<10000;i++){ promises.push(yourAsyncFunction(i)) } await Promise.all(promises) //Your final statement / operations //that will run once the loop ends //=> this approach will perform very fast as all the api call // will happen in parallal
fuente