4

Is it legit (or good practice) do a loop with a higher order function - like Array.map() - to perform some side effects ?

This is mostly a theoretical question since I notice that sometimes I found (or perform myself) some loops using the .map() method, like this:

let myObject = {...}
let myItemsArray = [ ... , ... ]

myItemsArray.map( (item, index) => {
    // do some side effect for ex: 
    myObject.item[index] = item
}

But I know that this map() method actually returns an array. So calling myItemsArray.map() is like I'm returning an array without assign it to any variable.

So the question, is this legit? Should I avoid this and use a classic for() loop or a .forEach() method?

Side question: one of the reasons I'm asking this is because I need to perform some loops on an async function so promises and await operators are involved, I remember that forEach() loops are not ideal on an async function, but wanted to know why.

Santiago
  • 361
  • 4
  • 21
  • 2
    Building an array you don't need is pointless, use `forEach` instead. But if you *are* doing asynchronous things it's possible you *do* need the array, because that's what `Promise.all` takes to resolve all of the promises. – jonrsharpe Dec 14 '20 at 09:29
  • 1
    you should just use `forEach` if you do'nt intend to actually map anything to a new array – TKoL Dec 14 '20 at 09:29
  • @jonrsharpe thanks, indeed my code resolves some promises so the Promise.All() takes the result in the end – Santiago Dec 14 '20 at 09:36
  • 1
    [Is performing a mapping operation without using returned value an antipattern?](https://stackoverflow.com/q/56903693) – VLAZ Dec 14 '20 at 09:38

1 Answers1

4

So the question, is this legit? Should I avoid this and use a classic for() loop or a .forEach() method?

If you aren't returning anything from the map function, then you should use forEach instead. You end up with the same result but you don't imply, to anyone maintaining your code, that you are returning something useful.

one of the reasons I'm asking this is because I need to perform some loops on an async function so promises and await operators are involved, I remember that forEach() loops are not ideal on an async function, but wanted to know why.

Neither forEach nor map will await if the function you pass to it returns a promise (which async functions do).

So there are three possible scenarios here:

// Your loop
...myItemsArray...
// Code that comes after the loop
...etc...

A: The items in the loop need to handled sequentially

Use a regular for () loop as the outer function won't pause.

B: The items in the loop can be handled in parallel and the code that comes after doesn't need to wait for it

Use a forEach.

C: The code that comes after needs to wait for everything in the loop to finish

Use a map. Pass the array of returned promises to Promise.all. Then await that.

Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
  • Oh I get it now. So the `forEach()` is like the most "volatile" method here, right? I didn't know that it runs in parallel though. Always think that it was like the `for()` loop. So I'm guessing that not returning anything forEach() also keeps the memory clean? Where using map without implying it on a variable the returned array could remain in the memory of the session ? – Santiago Dec 14 '20 at 09:42
  • Unless you `await` something, anything **asynchronous** in a loop will be done in parallel. With `for` an `await` will pause the whole loop. With `forEach` it will pause that specific function but the loop will continue on the other data in the meantime. – Quentin Dec 14 '20 at 09:43
  • "So I'm guessing that not returning anything forEach() also keeps the memory clean?" — No. – Quentin Dec 14 '20 at 09:44