Mam pętlę, która wywołuje metodę, która robi rzeczy asynchronicznie. Ta pętla może wywołać metodę wiele razy. Po tej pętli mam kolejną pętlę, która musi zostać wykonana tylko wtedy, gdy wszystkie czynności asynchroniczne są wykonane.
To ilustruje to, czego chcę:
for (i = 0; i < 5; i++) {
doSomeAsyncStuff();
}
for (i = 0; i < 5; i++) {
doSomeStuffOnlyWhenTheAsyncStuffIsFinish();
}
Nie znam obietnic, więc czy ktoś mógłby mi w tym pomóc?
Oto jak moje doSomeAsyncStuff()
zachowanie:
function doSomeAsyncStuff() {
var editor = generateCKEditor();
editor.on('instanceReady', function(evt) {
doSomeStuff();
// There should be the resolve() of the promises I think.
})
}
Może muszę zrobić coś takiego:
function doSomeAsyncStuff() {
var editor = generateCKEditor();
return new Promise(function(resolve,refuse) {
editor.on('instanceReady', function(evt) {
doSomeStuff();
resolve(true);
});
});
}
Ale nie jestem pewien składni.
s
na końcu nie maPromise
.Odpowiedzi:
Możesz użyć
Promise.all
( specyfikacja , MDN ) do tego: akceptuje kilka indywidualnych obietnic i zwraca jedną obietnicę, która jest rozwiązana, gdy wszystkie z nich zostały rozwiązane lub odrzucona, gdy któraś z nich zostanie odrzucona.Więc jeśli złożysz
doSomeAsyncStuff
obietnicę zwrotu, to: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 ma tutaj artykuł o obietnicach . Szczegółowo omawiam również obietnice w rozdziale 8 mojej książki JavaScript: The New Toys , linki w moim profilu, jeśli jesteś zainteresowany.
Oto przykład:
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();
Przykładowe dane wyjściowe (ze względu na to
Math.random
, co kończy się najpierw, może się różnić):źródło
Math.floor(Math.random() * 1000)
na(i * 1000)
await
jest to dozwolone. W tej chwili jedynym miejscem, którego możesz użyć,await
jest wnętrzeasync
funkcji. (W pewnym momencie będziesz mógł go również używać na najwyższym poziomie modułów.)Funkcja wielokrotnego użytku działa dobrze dla tego wzorca:
function awaitAll(count, asyncFn) { const promises = []; for (i = 0; i < count; ++i) { promises.push(asyncFn()); } return Promise.all(promises); }
Przykład OP:
awaitAll(5, doSomeAsyncStuff) .then(results => console.log('doSomeStuffOnlyWhenTheAsyncStuffIsFinished', results)) .catch(e => console.error(e));
Powiązany wzorzec to iteracja po tablicy i wykonanie operacji asynchronicznej na każdym elemencie:
function awaitAll(list, asyncFn) { const promises = []; list.forEach(x => { promises.push(asyncFn(x)); }); return Promise.all(promises); }
Przykład:
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));
źródło
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)), ]);
źródło
Oto kod, który napisałem dla siebie, aby zrozumieć podane tutaj odpowiedzi. Mam zapytania mangusty w pętli for, więc wstawiam tutaj,
asyncFunction
aby zająć jego miejsce. Mam nadzieję, że to pomoże każdemu. Możesz uruchomić ten skrypt w węźle lub w dowolnym z wielu środowisk wykonawczych 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!"); } )
źródło
/*** 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
źródło