Tengo un bucle que llama a un método que hace cosas de forma asíncrona. Este bucle puede llamar al método muchas veces. Después de este ciclo, tengo otro ciclo que debe ejecutarse solo cuando se completan todas las cosas asincrónicas.
Así que 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, ¿alguien podría ayudarme a lograr esto?
Así es como se comporta mi doSomeAsyncStuff() :
function doSomeAsyncStuff() { var editor = generateCKEditor(); editor.on('instanceReady', function(evt) { doSomeStuff(); // There should be the resolve() of the promises I think. }) }Tal vez tengo 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.
Puede usar Promise.all ( spec , MDN ) para eso: acepta un montón de promesas individuales y le devuelve una sola promesa que se resuelve cuando se resuelven todas las que le dio, o se rechaza cuando se rechaza cualquiera de ellas. .
Entonces, si hace que doSomeAsyncStuff devuelva una promesa, 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.
Aquí hay 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 Math.random , lo que termina primero puede variar):
Resolviendo 3 Resolviendo 2 Resolviendo 1 Resolviendo 4 Resolviendo 0 Todo hecho [0,1,2,3,4]
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); }OP ejemplo:
awaitAll(5, doSomeAsyncStuff) .then(results => console.log('doSomeStuffOnlyWhenTheAsyncStuffIsFinished', results)) .catch(e => console.error(e));Un patrón relacionado itera sobre una matriz y realiza 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));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)), ]);