Using async/await with a forEach loop
Sure the code does work, but I'm pretty sure it doesn't do what you expect it to do. It just fires off multiple asynchronous calls, but the printFiles
function does immediately return after that.
Reading in sequence
If you want to read the files in sequence, you cannot use forEach
indeed. Just use a modern for … of
loop instead, in which await
will work as expected:
async function printFiles () {
const files = await getFilePaths();
for (const file of files) {
const contents = await fs.readFile(file, 'utf8');
console.log(contents);
}
}
Reading in parallel
If you want to read the files in parallel, you cannot use forEach
indeed. Each of the async
callback function calls does return a promise, but you're throwing them away instead of awaiting them. Just use map
instead, and you can await the array of promises that you'll get with Promise.all
:
async function printFiles () {
const files = await getFilePaths();
await Promise.all(files.map(async (file) => {
const contents = await fs.readFile(file, 'utf8')
console.log(contents)
}));
}
await with array foreach containing async await
Use Array.prototype.map and Promise.all:
async function procesMultipleCandidates (data) {
let generatedResponse = []
await Promise.all(data.map(async (elem) => {
try {
// here candidate data is inserted into
let insertResponse = await insertionInCandidate(elem)
// and response need to be added into final response array
generatedResponse.push(insertResponse)
} catch (error) {
console.log('error'+ error);
}
}))
console.log('complete all') // gets loged first
return generatedResponse // return without waiting for process of
}
Or use a for/of
loop if you don't want the loop run concurrently:
async function procesMultipleCandidates (data) {
let generatedResponse = []
for(let elem of data) {
try {
// here candidate data is inserted into
let insertResponse = await insertionInCandidate(elem)
// and response need to be added into final response array
generatedResponse.push(insertResponse)
} catch (error) {
console.log('error'+ error);
}
}
console.log('complete all') // gets loged first
return generatedResponse // return without waiting for process of
}
What is the difference between async/await forEach and Promise.all + map
For Googlers who only saw the question title
Don't use async/await with forEach. Either use a for-of
loop, or use Promise.all()
with array.map()
.
If you have a general understanding on promises and async/await, the TL;DR on the differences between promise.all()
+ array.map()
and .forEach()
, is that it's impossible to await a forEach()
itself. Yes, you can run tasks in parallel in .forEach()
just like you can with .map()
, but you can't wait for all of those parallel tasks to finish, then do something once they've all finished. The whole point of using .map()
instead of .forEach()
is so you can get a list of promises, collect them with Promise.all()
, then await the whole thing. To see what I mean, just put a console.log('Finished')
after a forEach(async () => ...)
, and you'll see the "finished"
get logged out before everything has finished running in the .forEach()
loop. My advice would be to just not use .forEach()
with async logic (and really there's not a reason use ever use .forEach()
anymore these days, as I explain further down).
For those who need something a bit more in depth, the rest of this answer will dive into more detail, first giving a small review on promises, then showing an in-depth explanation on how these approaches behave differently and why .forEach()
is always the inferior solution when it comes to async/await.
A primer on promises and async/await
For the purposes of this discussion, you just have to remember that a promise is a special object that's promising that some task is going to be completed at some point in the future. You can attach listeners to a promise via .then()
, to get notified when the task is completed, and to receive the resolved value.
An async
function is simply a function that will always return a promise, no matter what. Even if you do async function doThing() { return 2 }
, it's not going to return 2, it's going to return a promise that immediately resolves to the value 2. Note that an asynchronous function will always return a promise immediately, even if it takes a long time for the function to run. This is why it's called a "promise", it's promising that the function will eventually finish running, and if you want to be notified for when the function has finished, you can add an event listener to it, via .then()
or await
.
await
is special syntax that lets you pause execution of an async function until a promise resolves. await
will only effect the function it's directly inside. Behind the scenes, await
is simply adding a special event listener to the promise's .then()
, so it can know when the promise resolves and what value it resolves with.
async fn1() {
async fn2() {
await myPromise // This pauses execution of fn2(), not fn1()!
}
...
}
async function fn1() {
function fn2() {
await myPromise // An error, because fn2() is not async.
}
...
}
If you can get a good grasp of these principles, then you should be able to understand the next sections.
for-of
A for-of
loop lets you execute your asynchronous tasks in serial, one after another. For example:
const delays = [1000, 1400, 1200];
// A function that will return a
// promise that resolves after the specified
// amount of time.
const wait = ms => new Promise(resolve => setTimeout(resolve, ms))
async function main() {
console.log('start')
for (const delay of delays) {
await wait(delay)
console.log('Finished waiting for the delay ' + delay)
}
console.log('finish')
}
main()
Write an async method with Parallel.Foreach loop that does call another async method to pull record
Well for one thing you can pretend that Parallel.ForEach
awaits your async
functions, but it doesn't. Instead you want to write something like this:
await Task.WhenAll(customers.Select(async customer =>
{
var processedCustomer = await MethodB(customer);
inboundCustomersFiles.AddRange(processedCustomer);
}));
Task.WhenAll
behaves like Parallel.ForEach
, but it's awaitable and it also awaits every task you pass to it before completing its own task. Hence when your await Task.WhenAll
completes, all the inner tasks have completely completed as well.
the process in methodB customerRecord takes time
That is very ambiguous. If you mean it takes server and/or IO time then that's fine, that's what async
is for. If you mean it takes your CPU time (ie it processes data locally for a long time), then you should spin up a task on a thread pool and await its completion. Note that this is not necessarily the default thread pool! Especially if you're writing an ASP.NET (core) application, you want a dedicated thread pool just for this stuff.
Use async await in forEach loop, node js
.forEach()
is not async-aware. Use a plain for/of
loop instead. In fact, pretty much stop using .forEach()
entirely these days as its basically obsolete. With block scope available now with let
and const
, there is no reason to use .forEach()
and it's extra function scope any more. Use a regular for
loop instead.
You can fix this particular code by changing to this:
exports.filterAverageRatingsEachSkillForStudent = async (req, res) => {
let receiver = req.query.receiver; //array of id ['ABBd23', 'SDSd242', 'dfNJ47']
try {
console.log('receiver id', receiver);
for (let id of reciever) {
console.log('Query String ', id);
const findRating = await FeedbackSchema.find({
receiver: id,
}).select('ratingL ratingS ratingR ratingW');
}
} catch (error) {
console.log(error.message);
}
}
It also appears that you must not have disclosed all the code for this function because it looks like you're trying to get findRating
, but then you never do anything with it.
The error you report about cannot set headers after they are sent does not occur in this code since that error is about sending multiple responses to the same incoming request and you don't send any responses in this code. So, help with that particular error would require disclosing more code or perhaps fixing this function will also fix that (we can't tell since we can't see the code that actually causes that error).
How to return data in foreach loop having multiple async functions inside
Try using Promise.all
Something like this =>
let result = await prepareStocks(data);
async function prepareStocks(incomingStocks) {
var stockCodes = incomingStocks.stocks.split(',');
var stockPrices = incomingStocks.trigger_prices.split(',');
var alertName = incomingStocks.alert_name;
const STOCKS = await Promise.all(stockCodes.map(async (stocks, index) => {
if (stockPrices[index] > 100) {
var stockCodes = {
code: stocks,
price: stockPrices[index],
orderType: (urls.buy.includes(alertName) ? 'BUY' : 'WATCH'),
target: await setSellPrice(stockPrices[index], 1),
stopLoss: await setStopLoss(stockPrices[index], 1),
}
return stockCodes;
}
})
return STOCKS;
}
How to parallel process multiple async task foreach loop
Since you are not awaiting the call to GetIsConnected()
in your AFTER example, the loop will continue and the value may or may not be checked against what it would be once the call to GetIsConnected()
is finished, what I think you'd want to do is add another method with a return type of Task
and let the method call GetIsConnected()
and await
it inside the method then call GetCarDetailsAsync()
if necessary:
//changed to return type of Task, as async void should be avoided
//unless this is an event handler method
private async Task Refresh()
//private async void Refresh() //change to this if event handler
{
List<Task> listOfTasks = new List<Task>();
foreach (var item in Cars.ToList<Carnet>())
{
listOfTasks.Add(GetCarDetails(item));
}
await Task.WhenAll(listOfTasks).ConfigureAwait(false);
}
//method to await the call to GetIsConnect()
//and then call GetCarDetailsAsync() if necessary
private async Task GetCarDetails(Carnet c)
{
await c.GetIsConnected();
if (c.IsConnected)
{
await c.GetCarDetailsAsync();
}
}
how to wait for async function in foreach loop
forEach
method doesn't wait for the async
operation to end before moving on to the next iteration.
You can use async-await
syntax along with for of
loop
async function foo() {
console.log('1');
for (const value of msg.reactions.cache) {
const data = await value.users.fetch();
console.log(data);
}
console.log('3');
}
foo();
Related Topics
Detect a Finger Swipe Through JavaScript on the Iphone and Android
How to Correctly Detect Orientation Change Using Phonegap on Ios
Sorting an Array of Objects by Property Values
Why Is Using the JavaScript Eval Function a Bad Idea
Execjs::Runtimeerror on Windows Trying to Follow Rubytutorial
Find Object by Id in an Array of JavaScript Objects
What Does This Symbol Mean in JavaScript
Get Selected Value in Dropdown List Using JavaScript
How to Access Previous Promise Results in a .Then() Chain
How to Print a Number With Commas as Thousands Separators in JavaScript
How to Use a Variable For a Key in a JavaScript Object Literal
How to Deal With Floating Point Number Precision in JavaScript
Replace HTML Page With Contents Retrieved Via Ajax
How to Display an Image Stored as Byte Array in Html/JavaScript
What Is the Purpose of the Var Keyword and When Should I Use It (Or Omit It)