Eu tenho um loop que chama um método que faz coisas de forma assíncrona. Este loop pode chamar o método muitas vezes. Após esse loop, tenho outro loop que precisa ser executado apenas quando todas as coisas assíncronas são concluídas.
Então, isso ilustra o que eu quero:
for (i = 0; i < 5; i++) {
doSomeAsyncStuff();
}
for (i = 0; i < 5; i++) {
doSomeStuffOnlyWhenTheAsyncStuffIsFinish();
}
Não estou muito familiarizado com promessas, então alguém poderia me ajudar a conseguir isso?
É assim que meu doSomeAsyncStuff()
comportamento:
function doSomeAsyncStuff() {
var editor = generateCKEditor();
editor.on('instanceReady', function(evt) {
doSomeStuff();
// There should be the resolve() of the promises I think.
})
}
Talvez eu tenha que fazer algo assim:
function doSomeAsyncStuff() {
var editor = generateCKEditor();
return new Promise(function(resolve,refuse) {
editor.on('instanceReady', function(evt) {
doSomeStuff();
resolve(true);
});
});
}
Mas não tenho certeza da sintaxe.
s
no final dePromise
.Respostas:
Você pode usar
Promise.all
( spec , MDN ) para isso: Aceita um monte de promessas individuais e devolve uma única promessa que é resolvida quando todas as que você deu são resolvidas, ou rejeitada quando qualquer uma delas é rejeitada.Então, se você
doSomeAsyncStuff
retornar uma promessa, então: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 tem um artigo sobre promessas aqui . Também abordo as promsies em detalhes no Capítulo 8 do meu livro JavaScript: The New Toys , links em meu perfil se você estiver interessado.
Aqui está um exemplo:
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();
Exemplo de saída (por causa do
Math.random
, o que termina primeiro pode variar):fonte
Math.floor(Math.random() * 1000)
para(i * 1000)
await
seja permitido. No momento, o único lugar que você pode usarawait
é dentro de umaasync
função. (Em algum ponto, você também poderá usá-lo no nível superior dos módulos.)Uma função reutilizável funciona bem para este padrão:
function awaitAll(count, asyncFn) { const promises = []; for (i = 0; i < count; ++i) { promises.push(asyncFn()); } return Promise.all(promises); }
Exemplo de OP:
awaitAll(5, doSomeAsyncStuff) .then(results => console.log('doSomeStuffOnlyWhenTheAsyncStuffIsFinished', results)) .catch(e => console.error(e));
Um padrão relacionado é iterar em uma matriz e executar uma operação assíncrona em cada item:
function awaitAll(list, asyncFn) { const promises = []; list.forEach(x => { promises.push(asyncFn(x)); }); return Promise.all(promises); }
Exemplo:
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));
fonte
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)), ]);
fonte
Aqui está o código que escrevi para mim mesmo, a fim de entender as respostas dadas aqui. Eu tenho consultas de mangusto em um loop for, então coloquei aqui o
asyncFunction
para ocupar seu lugar. Espero que ajude alguém. Você pode executar este script no nó ou em qualquer um dos muitos tempos de execução 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!"); } )
fonte
/*** 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
fonte