for loop vs .map() for making multiple API calls
Tags: javascript, api, async
Published: 2020-05-14 04:42:17

---
title: for loop vs .map() for making multiple API calls
published: true
description: Comparison of for, for...in, for...of loop vs .map() for making multiple API calls and the reason why map is faster.
tags: js, API, async
---
`Promise` / `async-await` is used for making API calls.

```js
const response = await fetch(`https://jsonplaceholder.typicode.com/todos/1`)
const todo = await response.json()
console.log(todo)
```

Assuming I have a list of ids of todo items and I want the `title` of all them then I shall use the below snippet inside an `async` function
```js
const todoIdList = [1, 2, 3, 4]
for (const id of todoIdList) {
  const response = await fetch(`https://jsonplaceholder.typicode.com/todos/${id}`)
  const todo = await response.json()
  console.log(todo.title)
}
```
This same can be written with any of these `for`, `for...in`, `for...of` loops.

Assuming each API request arbitrarily takes 100ms exactly, the total time taken for getting the details of four todo items will have to be greater than 400ms if we use any of the above-mentioned loops.

This execution time can be drastically reduced by using `.map()`.
```js
const todoIdList = [1, 2, 3, 4]
await Promise.all(
  todoIdList.map(async (id) => {
    const response = await fetch(`https://jsonplaceholder.typicode.com/todos/${id}`)
    const todo = await response.json()
    console.log(todo.title)
  })
)
```
Adding timers
```js
const todoIdList = [1, 2, 3, 4]
console.time('for {}');
for (const id of todoIdList) {
  const response = await fetch(`https://jsonplaceholder.typicode.com/todos/${id}`)
  const todo = await response.json()
  console.log(todo.title)
}
console.timeEnd('for {}');

console.time('.map()');
await Promise.all(
  todoIdList.map(async (id) => {
    const response = await fetch(`https://jsonplaceholder.typicode.com/todos/${id}`)
    const todo = await response.json()
    console.log(todo.title)
  })
)
console.timeEnd('.map()');
```

## The Reason
### for loop
`for` loop goes to the next iteration only after the whole block's execution is completed. In the above scenario only after both the promises(await) gets **resolved**, for loop moves to the next iteration and makes the API call for the next todo item.

### .map()
`.map()` moves on to the next item as soon as a  promise is **returned**. It does not wait until the promise is resolved. In the above scenario, .map() does not wait until the response for todo items comes from the server. It makes all the API calls one by one and for each API call it makes, a respective promise is returned. `Promise.all` waits until all of these promises are resolved.

`async/await` is *syntactic sugar* for `Promises`

It will be more clear if the same code is written without `async/await`
```js
const todoIdList = [1, 2, 3, 4]
console.time('.map()')
Promise.all(
  todoIdList.map(id => {
    return new Promise((resolve) => {
      fetch(`https://jsonplaceholder.typicode.com/todos/${id}`)
        .then(response => {
          return new Promise(() => {
            response.json()
              .then(todo => {
                console.log(todo.title)
                resolve()
              })
          })
        })
    })
  })
)
.then(() => {
  console.timeEnd('.map()');
})
```
It is not possible to mimic the respective code for `for` loop by replacing `async/await` with `Promises` because, the control which triggers the next iteration will have to written within the `.then()` block. This piece of code will have to be created within the JS engine.

All the snippets are working code, you can try it directly in the browser console.
Note:
- snippets need to be enclosed within an async function except for the last one
- use `Axios` or any other suitable library if `fetch` is not available.

Let me know if there is an even better and easy/short way of making API calls.

Also, do not forget to mention any mistakes I've made or tips, suggestions to improve this content.