0

This code snippet is taken from google developers:

// map some URLs to json-promises
const jsonPromises = urls.map(async url => {
  const response = await fetch(url);
  return response.json();
});

I understand that at the end jsonPromises is going to be an array of Promises. However, i'm not completely sure how that happens.

According to my understanding, when execution gets to this line const response = await fetch(url); it moves it from call stack to Web Api, does the same to return response.json(); and moves to the next url from urls. Is it correct ? I understand how event loop works when it comes to simple setTimeout , but this example confuses me a lot.

Noob
  • 2,247
  • 4
  • 20
  • 31
  • Yes, kind of. ... – Jonas Wilms Dec 06 '19 at 20:53
  • @JonasWilms could you please explain step by step what happens to clear my doubts ? – Noob Dec 06 '19 at 20:54
  • Hey @Noob since Array.map() is not an async function, it won't wait for every async callback it runs one element to complete before running it over the next element. As for reponse.json(), that just returns a promise that wraps the parsed body of a response object. Hope that clears things up a little? More on fetch here: https://developers.google.com/web/updates/2015/03/introduction-to-fetch – adamz4008 Dec 06 '19 at 20:58
  • @adamz4008 sure, i agree with you. I understand what you are saying, my question is how it all works in relation to event loop. Your comment does not answer that. – Noob Dec 06 '19 at 21:04

2 Answers2

1

Since async functions return a promise, think of the example as any other promise-returning function:

// map happens synchronously and doesn't wait for anything
const map = (arr, cb) => {
  const mapped = [];
  for (const [i, element] of arr.entries()) {
    mapped.push(cb(element))
  }
  return mapped;
}

// just return a promise that resolves in 5 seconds with the uppercased string
const promiseFn = url => {
  return new Promise(resolve => setTimeout(() => resolve(url.toUpperCase()), 5000))
}

const promiseArray = map(['url', 'url', 'url'], promiseFn)

All the promises returned by the async callback are pushed synchronously. Their states are modified asynchronously.

If on the other hand you're looking for the difference between setTimeout and a Promise vis-a-vis the event loop, check the accepted answer here: What is the relationship between event loop and Promise

adamz4008
  • 660
  • 4
  • 10
1

Here's what happens:

1) The .map function runs, and executes the callback for each element (the async function). The function calls fetch, which starts some under the hood magic inside the engine. fetch returns a Promise. The await gets reached, which halts the functions execution. The call to the function done by .map evaluates to a promise. .map collects all those promises and stores them in an array and returns the array.

2) Somewhen, one of the fetches running under the hood has etablished a connection, and calls back into JS and resolves the fetch promise. That causes the async function call to go on. res.json() gets called, which causes the engine to collect all the packets from the connection and parse it as JSON under the hood. That again returns a Promise, which gets awaited, which causes the execution to stop again.

3) Somewhen, one of the connections end, and the whole response is available as JSON. The promise resolves, the async function call continues execution, returns, which causes the promise (the one in the array) to be resolved.

Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151
  • I'm sorry, i'm still processing your answer. I'm confused by this part a bit. `The call to the function done by .map evaluates to a promise.` I understand that `The await gets reached, which halts the functions execution.`, but why after that it evaluates to a promise? – Noob Dec 07 '19 at 18:27
  • What else should it evaluate to? The `return` was not reached yet. At that point in time, we only know that the function will *return something in the future*. It *promises* to do so. – Jonas Wilms Dec 07 '19 at 18:30