workshopper / learnyounode

Learn You The Node.js For Much Win! An intro to Node.js via a set of self-guided workshops.
Other
7.24k stars 1.84k forks source link

juggling async issue #713

Closed gkatsanos closed 3 years ago

gkatsanos commented 3 years ago
const http = require("http");

let count = 0;
  let finalResponse = [];

for (let i = 0; i < 3; i++) {
  http.get(process.argv[2 + i], (response) => {
    let aggregatedResponse = "";
    response.setEncoding("utf8");
    response.on("data", (chunk) => {
      aggregatedResponse += chunk;
    });
    response.on("end", () => {
      console.log(i, aggregatedResponse);
      finalResponse[i] = aggregatedResponse;
      // console.log("finalResponse in event", finalResponse);
      count++;
      if (count === 3) {
        // console.log("count", count);
        console.log("finalResponse", finalResponse);
        // console.log("aggregatedResponse", aggregatedResponse);
        // finalResponse.forEach((value) => {
        //   // console.log(value);
        // });
      }
    });
  });
}

I saw the solution.js but wondering why my code (without the bl library) fails. seems that concatenating chunks of responses ends up in empty "" elements in the finalResponse array

francesmcmullin commented 3 years ago

I think there are a some problems here - one with the scope of your i variable, and one with the position of your if (count === 3) block. Try to remember that any time you create and pass a new function, you do not know when that function willl be run, and the outer variables might change in the meantime. It might be instructive to observe the timing of various parts of your code. I suggest running something like this and see if you can understand better what's going on:

const http = require("http");

let count = 0;

for (let i = 0; i < 3; i++) {
  let finalResponse = [];
  console.log('beginning http get', i);
  http.get(process.argv[2 + i], (response) => {
    console.log('beginning http callback', i);
    let aggregatedResponse = "";
    response.setEncoding("utf8");
    response.on("data", (chunk) => {
      aggregatedResponse += chunk;
    });
    response.on("end", () => {
      console.log('received http end, saving full response', i, aggregatedResponse);
      finalResponse[i] = aggregatedResponse;
      // console.log("finalResponse in event", finalResponse);
      count++;
    });
    console.log('checking if all responses have been saved', i, count);
    if (count === 3) {
      // console.log("count", count);
      // console.log("finalResponse", finalResponse);
      // console.log("aggregatedResponse", aggregatedResponse);
      finalResponse.forEach((value) => {
        console.log(value);
      });
    }
  });
}
francesmcmullin commented 3 years ago

Ah, yes, that's quite hard to read! But we can reconstruct the log with a little effort, it looks like this:

beginning http get 0
beginning http get 1
beginning http get 2
beginning http callback 2
received http end, saving full response 2 He's got a massive boil-over also he hasn't got a bush bash. It'll be give it a burl where lets get some piker. 
beginning http callback 0
checking if all responses have been saved 0 1
beginning http callback 1
checking if all responses have been saved 1 1
received http end, saving full response 0 She'll be right bonza no dramas as busy as a rack off. Watch out for the rort piece of piss gutful of roo bar. As stands out like uluru heaps as cunning as a brizzie. As cunning as a shag on a rock also as cross as a barbie. As busy as a ridgy-didge piece of piss as busy as a fremantle doctor. 
received http end, saving full response 1 It'll be bushie heaps get a dog up ya bogan. Lets get some bathers where stands out like a rip snorter. 

Which looks like it's still checking the response count before it should, but it sounds like you've already corrected the location of the if count === 3 block, and I was actually wrong about the variable scoping (let inside a for loop is really helpful!), so I'm not sure what the remaining problem is, could you paste the latest version of code you're running?