У меня есть цикл, который вызывает метод, выполняющий асинхронно. Этот цикл может вызывать метод много раз. После этого цикла у меня есть еще один цикл, который нужно выполнить, только когда все асинхронные вещи будут выполнены.
Итак, это иллюстрирует то, что я хочу:
for (i = 0; i < 5; i++) {
doSomeAsyncStuff();
}
for (i = 0; i < 5; i++) {
doSomeStuffOnlyWhenTheAsyncStuffIsFinish();
}
Я не очень хорошо разбираюсь в обещаниях, может ли кто-нибудь помочь мне в этом?
Вот как doSomeAsyncStuff()
себя ведет я:
function doSomeAsyncStuff() {
var editor = generateCKEditor();
editor.on('instanceReady', function(evt) {
doSomeStuff();
// There should be the resolve() of the promises I think.
})
}
Может мне надо сделать что-то вроде этого:
function doSomeAsyncStuff() {
var editor = generateCKEditor();
return new Promise(function(resolve,refuse) {
editor.on('instanceReady', function(evt) {
doSomeStuff();
resolve(true);
});
});
}
Но я не уверен в синтаксисе.
s
в конце нетPromise
.Ответы:
Для этого вы можете использовать
Promise.all
( spec , MDN ): он принимает кучу отдельных обещаний и возвращает вам одно обещание, которое выполняется, когда все из них, которые вы ему дали, разрешены, или отклоняется, когда любое из них отклоняется.Итак, если вы вернете
doSomeAsyncStuff
обещание, тогда: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 есть статья на обещания здесь . Я также подробно рассказываю о выпускных мероприятиях в главе 8 моей книги « JavaScript: новые игрушки» , ссылки в моем профиле, если вам интересно.
Вот пример:
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();
Пример вывода (из-за того
Math.random
, что заканчивается первым, может отличаться):источник
Math.floor(Math.random() * 1000)
на(i * 1000)
await
разрешенном контексте . На данный момент единственное место, которое вы можете использовать,await
- это внутриasync
функции. (В какой-то момент вы также сможете использовать его на верхнем уровне модулей.)Многоразовая функция отлично подходит для этого шаблона:
function awaitAll(count, asyncFn) { const promises = []; for (i = 0; i < count; ++i) { promises.push(asyncFn()); } return Promise.all(promises); }
Пример OP:
awaitAll(5, doSomeAsyncStuff) .then(results => console.log('doSomeStuffOnlyWhenTheAsyncStuffIsFinished', results)) .catch(e => console.error(e));
Связанный шаблон - это итерация по массиву и выполнение асинхронной операции для каждого элемента:
function awaitAll(list, asyncFn) { const promises = []; list.forEach(x => { promises.push(asyncFn(x)); }); return Promise.all(promises); }
Пример:
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)), ]);
источник
Вот код, который я написал для себя, чтобы понять приведенные здесь ответы. У меня есть запросы мангуста в цикле for, поэтому я поставил здесь
asyncFunction
вместо него. Надеюсь, это кому-нибудь поможет. Вы можете запустить этот сценарий в узле или в любой из многих сред выполнения 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!"); } )
источник
/*** 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
источник