Calling an asynchronous function within a for loop in JavaScript
Since you're running through an array, you can simply use forEach
which provides the list item, and the index in the callback. Iteration will have its own scope.
list.forEach(function(listItem, index){
mc_cli.get(listItem, function(err, response) {
do_something(index);
});
});
calling an async function inside for loop in JavaScript / node js
Just put async
in front of function test.
async function test(req, res) {…
If you want to await
a promise, then the function that's using await
needs to be async
function.
Asynchronous Process inside a javascript for loop
The for
loop runs immediately to completion while all your asynchronous operations are started. When they complete some time in the future and call their callbacks, the value of your loop index variable i
will be at its last value for all the callbacks.
This is because the for
loop does not wait for an asynchronous operation to complete before continuing on to the next iteration of the loop and because the async callbacks are called some time in the future. Thus, the loop completes its iterations and THEN the callbacks get called when those async operations finish. As such, the loop index is "done" and sitting at its final value for all the callbacks.
To work around this, you have to uniquely save the loop index separately for each callback. In Javascript, the way to do that is to capture it in a function closure. That can either be done be creating an inline function closure specifically for this purpose (first example shown below) or you can create an external function that you pass the index to and let it maintain the index uniquely for you (second example shown below).
As of 2016, if you have a fully up-to-spec ES6 implementation of Javascript, you can also use let
to define the for
loop variable and it will be uniquely defined for each iteration of the for
loop (third implementation below). But, note this is a late implementation feature in ES6 implementations so you have to make sure your execution environment supports that option.
Use .forEach() to iterate since it creates its own function closure
someArray.forEach(function(item, i) {
asynchronousProcess(function(item) {
console.log(i);
});
});
Create Your Own Function Closure Using an IIFE
var j = 10;
for (var i = 0; i < j; i++) {
(function(cntr) {
// here the value of i was passed into as the argument cntr
// and will be captured in this function closure so each
// iteration of the loop can have it's own value
asynchronousProcess(function() {
console.log(cntr);
});
})(i);
}
Create or Modify External Function and Pass it the Variable
If you can modify the asynchronousProcess()
function, then you could just pass the value in there and have the asynchronousProcess()
function the cntr back to the callback like this:
var j = 10;
for (var i = 0; i < j; i++) {
asynchronousProcess(i, function(cntr) {
console.log(cntr);
});
}
Use ES6 let
If you have a Javascript execution environment that fully supports ES6, you can use let
in your for
loop like this:
const j = 10;
for (let i = 0; i < j; i++) {
asynchronousProcess(function() {
console.log(i);
});
}
let
declared in a for
loop declaration like this will create a unique value of i
for each invocation of the loop (which is what you want).
Serializing with promises and async/await
If your async function returns a promise, and you want to serialize your async operations to run one after another instead of in parallel and you're running in a modern environment that supports async
and await
, then you have more options.
async function someFunction() {
const j = 10;
for (let i = 0; i < j; i++) {
// wait for the promise to resolve before advancing the for loop
await asynchronousProcess();
console.log(i);
}
}
This will make sure that only one call to asynchronousProcess()
is in flight at a time and the for
loop won't even advance until each one is done. This is different than the previous schemes that all ran your asynchronous operations in parallel so it depends entirely upon which design you want. Note: await
works with a promise so your function has to return a promise that is resolved/rejected when the asynchronous operation is complete. Also, note that in order to use await
, the containing function must be declared async
.
Run asynchronous operations in parallel and use Promise.all()
to collect results in order
function someFunction() {
let promises = [];
for (let i = 0; i < 10; i++) {
promises.push(asynchonousProcessThatReturnsPromise());
}
return Promise.all(promises);
}
someFunction().then(results => {
// array of results in order here
console.log(results);
}).catch(err => {
console.log(err);
});
Calling async function inside a loop
You should use Promise.all
.
Construct an Array of Promises and then use the method to wait for all promises to fulfill, after that you can use the array in the correct order:
let hashArray = ["QmTgsbm...nqswTvS7Db",
"QmR6Eum...uZuUckegjt",
"QmdG1F8...znnuNJDAsd6",
]
// construct Array of promises
let hashes = hashArray.map(hash => ipfsRetrieve(hash));
Promise.all(hashes).then(dataArray => {
// work with the data
console.log(dataArray)
});
How to call async-await API calls inside forEach loop?
the easiest way to transform your code into code that works as you intend is to replace
selectedTodos.forEach(async (todo) => {
with
await Promise.all(selectedTodos.map(async (todo) => {
assuming you're inside an asynchronous function. How it works is selectedTodos.map returns an array of promises, and Promise.all waits for them all to be resolved before moving on. There are similar methods under the Promise class, too.
A classic
for(const todo of selectedTodos) {
await actions
}
works, too. But if you like more imperative code, the first example is the same
How to add await in a for loop to wait for function call?
This is a generic example to show how asynchronous code can be used along with readdir and a loop
const fs = require("fs")
function pr(f) {
return new Promise((resolve, _reject) => {
setTimeout(function () {
resolve("got file " + f)
}, 500)
})
}
const pth = __dirname; // whatever directory path with something in it...
fs.readdir(pth, async (err, files) => {
// Don't use a forEach syntax as it doesn't support asynchronous code,
// it would not throw an error, but the promises won't be
// resolved inside the loop with forEach.
for (const f of files) {
const msg = await pr(f);
console.log(msg)
}
})
And here is an example that should correspond to your case (it didn't not fully understand where you call the store asset and how you use the files iterator but it should illustrate the point)
fs.readdir(testFolder, async (err, files) => {
// ...
for (const file in files) {
await storeAsset();
}
// ...
});
Waiting for async function in for loop
You do it in a wrong way, you don't wait anything in you for-loop
.
return await Promise.all(all_vacations);
does not work, because all_vacations
is not a Promise array.
In your case, we have many way to do this, my way just is a example: Create a array to store all promises what have been created in your for-loop
, then wait until the all promises finished by Promise.all
syntax.
async function loop_through_vacations(vacations_incomplete, pool) {
var all_vacations = [];
var promises = []; // store all promise
for (var vacation_data of vacations_incomplete) {
var vacation_at_index = new vac.Vacation(vacation_data.id, vacation_data.destination, vacation_data.description, vacation_data.attendee_creator_id);
promises.push( // push your promise to a store - promises
vacation_at_index.find_creator(pool)
.then(() => {
all_vacations.push(vacation_at_index)
})
.catch((err) => {
console.log(err); // Skip error???
})
);
}
await Promise.all(promises); // wait until all promises finished
return all_vacations;
}
I don't know why you use async/await
mix with callback
style, I recommend async/await
for any case:
Mix style:
function get_all_vacations(callback) {
var sql_vacations_query = "SELECT * FROM vacation";
pool.query(sql_vacations_query, async function(error, vacations_query_result) { // async
if (error) {
console.log("error in vacations query " + error);
return callback(error); // return to break process
}
var all_complete = await loop_through_vacations(vacations_query_result.rows, pool); // await
callback(null, all_complete);
});
}
async/await
:
async function get_all_vacations() {
var sql_vacations_query = "SELECT * FROM vacation";
var rows = await new Promise((resolve, reject) => {
pool.query(sql_vacations_query, function(error, vacations_query_result) {
if (error) {
console.log("error in vacations query " + error);
return reject(error);
}
resolve(vacations_query_result.rows);
});
})
var all_complete = await loop_through_vacations(rows, pool); // await
return all_complete;
}
How to wait for results from multiple async methods wrapped in a for loop?
I think I know what you try to achieve, and the issue you are having, this.getFinalDisplayResults()
is executed before you have the results because the logic inside the for loop is asynchronous, so the fix would be.
async function getDataFromBackend () {
for(let type in ["player", "team", "event"]) {
const searchResult = await this.searchService.getSearchResult(type).toPromise()
if(type === "player")
this.player_search_results_full = this.getPlayerSearchResults(searchResult, search_string);
if(type === "team")
this.team_search_results_full = this.getTeamSearchResults(searchResult, search_string);
if(type === "event")
this.event_search_results_full = this.getEventSearchResults(searchResult, search_string);
}
}
async function getFinalDisplayResults() {
await getDataFromBackend(); // this will ensure you have the data, before you do the rest of the process
//rest of the logic here
}
Related Topics
Swift: How to Get Image Name from Assets
Osx/Swift: Call a Function When Internet Connection Is Established/Restored
How to Create Travelling Wave in Spritekit
Close Window Based on Kcgwindowname Value
Swift Execute Command Line Command in Sandbox Mode
Swift Generics and Protocol Extensions
Cocos2D Fcm Push Notification Not Working
How Does Swift's Int Literal to Float Inference Work
How to Get The Advantages of Scenekit's Level Editor Programatically
Sending Array Data from One View Controller to Another
Populate a Multidimensional Array with a Loop
Swiftui List .Ondelete: Index Out of Range
How to Put a View with Loadmore Button in UItableview After The Cell
Can't Unwrap Optional.None When Setting Window Background Color