0

I'm using a many to many relation with TypeOrm who is needing Ids to find the subcategories of an article.

The problem is that the map is not awaiting to push the result in the array.

Here is my map function with the list and the logs:

const subcategories = articleDto.subcategoriesIds.split(',').map(x => +x)
const subcategoriesList = []
    
await subcategories.map(async (subcategoryId) => {
    console.log('start:' + subcategoryId)
    const category = await this.subcategoriesService.getSubcategoryById(subcategoryId);
    console.log('mid:' + subcategoryId)
    await subcategoriesList.push(category);
    console.log('end:' + subcategoryId)
});

console.log('### ' + subcategories);
console.log('### ' + subcategoriesList);

Here is the output of the logs:

start:2
start:3
### 2,3
### 
mid:2
end:2
mid:3
end:3

I'm not understanding why the result is not awaited, thanks for the help if you know how to manage with this problem.

EDIT: Solved this issue by adding a Promise.all using map inside

const subcategories = articleDto.subcategoriesIds.split(',').map(x => +x);

const subcategoriesList = await Promise.all(subcategories.map((subcategoryId) => {
      return new Promise((resolve => {
        this.subcategoriesService.getSubcategoryById(subcategoryId).then(result => {
          resolve(result);
        });
      }))
    }));
Hugo Sohm
  • 2,872
  • 4
  • 23
  • 40
  • 2
    Please don't use `.map` for simple iteration. Use `.forEach` or an actual loop instead. – VLAZ Jan 25 '21 at 19:32
  • `.forEach` is not asynchronous, I will use promises instead of map. – Hugo Sohm Jan 25 '21 at 19:37
  • The point is not to misuse `.map`. It's not just a tool for iterating over a dataset. It's for performing *mapping*. – VLAZ Jan 25 '21 at 19:39
  • Yes I understand, so the solution is to use a `.for` loop because `.forEach` is not asynchronous ? – Hugo Sohm Jan 25 '21 at 19:41
  • 1
    You can use a regular loop if you want to process these sequentially or fire off all requests, then await them all at once with `Promise.all`. Depends on whether you want to process these sequentially or in parallel. Since there doesn't seem like there is dependencies between your requests, `Promise.all` seems like the better choice. That's what the linked duplicate shows. – VLAZ Jan 25 '21 at 19:54
  • Yes I will use the `Promise.all` with the array of promises, thanks for your answers. – Hugo Sohm Jan 25 '21 at 19:57

1 Answers1

0

Array prototype methods don't await even if they are async. The code fires in a synchronous manner still. If you need these to await you can do

const subcategories = articleDto.subcategoriesIds.split(',').map(x => +x)
const subcategoriesList = []

for (const subCategoryId of subcategories) {
  console.log('start:' + subcategoryId)
  const category = await this.subcategoriesService.getSubcategoryById(subcategoryId);
  console.log('mid:' + subcategoryId)
  await subcategoriesList.push(category);
  console.log('end:' + subcategoryId);
}

console.log('### ' + subcategories);
console.log('### ' + subcategoriesList);
Jay McDoniel
  • 57,339
  • 7
  • 135
  • 147
  • Thanks for the answer but I try to develop without using for function... Is it not possible to use promise instead of await to await all promises after iterations ? – Hugo Sohm Jan 25 '21 at 19:34
  • Why develop without using a for functions? There's litereally answers all over saying this is how to do exactly what you're looking for? I suppose if you _really_ want to avoid `for` loops you could `map` it and then `await Promise.all(returnedArrayFromSubcategories.map)` – Jay McDoniel Jan 25 '21 at 19:41
  • I don't use the for loop following the [airbnb javascript style guide](https://airbnb.io/javascript/#iterators-and-generators) – Hugo Sohm Jan 26 '21 at 00:13
  • Interesting. While array functions are generally easier to read, and more succinct, there are absolutely times to use `for of` instead of `map` or `every`. This being one of them. Another being when performance is what you're looking for. – Jay McDoniel Jan 26 '21 at 00:28
  • Yes you'r right, I just always used to follow this style guide used in many companies maybe sometimes by mistake. I will check the `for` loop in more details tomorrow ! – Hugo Sohm Jan 26 '21 at 00:34