Whats the smartest / cleanest way to iterate async over arrays (or objs)?
Checkout the async library, it's made for control flow (async stuff) and it has a lot of methods for array stuff: each, filter, map. Check the documentation on github. Here's what you probably need:
each(arr, iterator, callback)
Applies an iterator function to each item in an array, in parallel. The iterator is called with an item from the list and a callback for when it has finished. If the iterator passes an error to this callback, the main callback for the each
function is immediately called with the error.
eachSeries(arr, iterator, callback)
The same as each
only the iterator is applied to each item in the array in series. The next iterator is only called once the current one has completed processing. This means the iterator functions will complete in order.
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)
}));
}
Iterate over async function
Promise is the best solution for handling asynchronous operations.
Promise.all(search_words.map(function(keyword) { return new Promise(function(resolve, reject) { request(base_url + keyword + "&l=", function(err, resp, body) { if (err) { return reject(err); } $ = cheerio.load(body); resolve([keyword, $("#searchCount")[0].children[0].data.split(" ").reverse()[0]]); }); });})).then(function(stats) { console.log(stats);});
Returning array populated in loop by async function
The problem here is that you are using a plain for
loop to traverse the animals
array. Loops in NodeJS won't wait for the promise of the current iteration to resolve before moving onto the next, so the loop will finish before you have resolved your promises.
The best thing to do is to construct an array of promises you want to resolve, and then call Promise.all
on that array.
async function getAnimalSounds(animals){
const promises = animals.map(a => asynchronously_fetch_sound(a))
const sounds = await Promise.all(promises)
return sounds
}
Or if you're happy to use the Bluebird library (docs here), you can do this:
const Bluebird = require('bluebird') // import Bluebird library
async function getAnimalSounds(animals){
const sounds = await Bluebird.map(animals, (a) => asynchronously_fetch_sound(a))
return sounds
}
Remember that since you have written an async function, you will need to wait for it to resolve before doing anything with its output; either by await
ing it or by calling .then(...)
.
Best way to wait for .forEach() to complete
If there is no asynchronous code inside the forEach
, forEach
is not asynchronous, for example in this code:
array.forEach(function(item){
//iterate on something
});
alert("Foreach DONE !");
you will see the alert after forEach
finished.
Otherwise (You have something asynchronous inside), you can wrap the forEach
loop in a Promise:
var bar = new Promise((resolve, reject) => {
foo.forEach((value, index, array) => {
console.log(value);
if (index === array.length -1) resolve();
});
});
bar.then(() => {
console.log('All done!');
});
Credit: @rolando-benjamin-vaz-ferreira
How to know if a promise inside a loop has ended?
You can solve this using Promise.all
Here is an example and here some useful documentation
the example is using map instead of a for loop to iterate over the array.
I haven't tested it but that should work
Promise.all(
this.data_array.map((data) => {
console.log('Inserting object number ' + data.id);
return this.database.insertService(data);
})
)
.then((result) => console.log('done', result))
.catch((error) => console.log(error));
Return array after forEach loop (async) is finished
I don't understand why you loop over an array of IDs and use findOne
to retrieve your objects, you could use something like this :
await this.Model.find({_id: {$in: modelIds}});
Also, instead of using forEach
to push in an array, why don't you use map
?
I think you could do something like that :
async function recover(modelIds) {
return modelsIds.map(async (modelId, i) => {
const query = "..."; // your query with the id
return await this.Model.findOne(query);
})
}
And the surround your function call with try/catch
to catch errors trhown during your function execution.
Asynchronously loop through array with key
You don't need a third-party library to accomplish this. Just use Promise.all()
and Array.prototype.map()
.
const customerDetails = await Promise.all(
customers.map(customer => details(customer))
);
How to wait for a loop to finish in an async function before executing code in another async function?
If you change your method like this, that should work as expected:
async selectFile() {
await Promise.all(
this.Form.PostFiles.map(async(el, i) => {
const File = this.Form.PostFiles[i][0];
await this.uploadFile(File)
})
);
}
Related Topics
Inconsistent Scenekit Framerate
Reading Currently Playing Track in MACos Using Scriptingbridge Not Working
Arkit - Viewport Size VS Real Screen Resolution
How Replace Position++ Code to Make It Swift 3 Compatible
Localizewithformat and Variadic Arguments in Swift
Swift Parsing Attribute Name for Given Elementname
How to Set the Alpha of an Uiimage in Swift Programmatically
Writing Data to an Nsoutputstream in Swift 3
Are the #If Debug Statements Really Needed for Previews in Swiftui to Remove It in a Release Build
Getting Optional("") When Trying to Get Value from Keychain
How to Reference Swift Playground Itself
Xcode Beta 6 "Type of Expression Is Ambiguous Without More Context" Navigationlink
Swiftui - Wait Until Firestore Getdocuments() Is Finished Before Moving On
How to Make Physics Bodies Stick to Nodes Anchor Points
How to Add Kerning to a Textfield in Swiftui
Segue from a Slpagingviewswift Vc and Dismiss the Destination Vc to Return
Could Not Find an Overload for '/' That Accepts the Supplied Arguments
Showing Cells in Demands in Uicollectionview with Vertical Infinite Scroll