0

I'm having trouble understanding the difference between the 2 approaches taken.

I have a certain Promise.All which works as expected, after that, a then function is used to extract data from the responses. I can't figure out why if I use the forEach approach i get printed the data, but if I use the map approach i get return Promises.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script>
        Promise.all(
            ["koop4", "gVenturi", "aledocdonnini" ].map(  user => fetch( 'https://api.github.com/users/'+user+'/repos', { method: 'GET'})  )
        ).then( res => {
            // this works properly
            const data = [];
            res.forEach( async r  => { 
              data.push(await r.json()); 
            });
            return data;
            // this return promises
            /* return res.map( async r  => await r.json() n)*/
        }).then(console.log)
    </script>
</head>
<body>
    
</body>
</html>
Robdll
  • 5,865
  • 7
  • 31
  • 51
  • don't use `await` in `forEach` - it doesn't work like you think - there's a question around here about it, let me find it for you – Jaromanda X Apr 17 '19 at 08:46
  • actually the for each approach works as intended – Robdll Apr 17 '19 at 08:46
  • no it doesn't ... data will be `[]` when you return it - what you see in the console is a mirage (trust me) – Jaromanda X Apr 17 '19 at 08:47
  • change `.then(console.log)` to `.then((results => console.log(JSON.stringify(results))))` and you'll see that you are NOT getting the results when you think you are - the console lies :p it shows the content of objects evaluated when you look at it, not when it is logged – Jaromanda X Apr 17 '19 at 08:51
  • Have a look at the output when you run the snippet ... it is `[]` ... not what the actual console shows, is it – Jaromanda X Apr 17 '19 at 08:52
  • `data` in `console.log` is evaluated at runtime by the console, hence it's written **asynchrously**. If you log the original value, it will be an empty array, as Jaromanda is saying. Besides, this is just overcomplicated. – briosheje Apr 17 '19 at 08:52
  • that's what I just said :p – Jaromanda X Apr 17 '19 at 08:53
  • @JaromandaX yup, sorry, I was trying to explain that slightly before you posted your answer, didn't see that coming. – briosheje Apr 17 '19 at 08:53
  • I get what you all mean, thanks for the clarification – Robdll Apr 17 '19 at 08:57
  • `for (const r of res) { ... }` will work with `await` – Keith Apr 17 '19 at 08:58
  • @Koop4 further reading can be found here: https://stackoverflow.com/questions/37576685/using-async-await-with-a-foreach-loop – briosheje Apr 17 '19 at 08:58

1 Answers1

2

Use map instead of forEach

Promise.all([
    "koop4",
    "gVenturi",
    "aledocdonnini"
].map(user => fetch("https://api.github.com/users/" + user + "/repos", {method: "GET"})))
    .then(res => Promise.all(res.map(r => r.json())))
    .then(console.log);

or do .json() in first map witch is cleaner in my opinion

Promise.all([
    "koop4",
    "gVenturi",
    "aledocdonnini"
].map(user => fetch("https://api.github.com/users/" + user + "/repos", {method: "GET"}).then(r => r.json())))
    .then(console.log);
ponury-kostek
  • 7,824
  • 4
  • 23
  • 31