Link to home
Start Free TrialLog in
Avatar of Bruce Gust
Bruce GustFlag for United States of America

asked on

What's the significant of "return" in this code?

Here is a part of my code:

if (url === "/message" && method === "POST") {
    const body = [];
    req.on("data", chunk => {
      console.log(chunk);
      body.push(chunk);
    });
     [b]req.on("end", () => {[/b]
      const parsedBody = Buffer.concat(body).toString();
      const message = parsedBody.split("=")[1];
      fs.writeFile("message.txt", message, err => {
        res.statusCode = 302;
        res.setHeader("Location", "/");
        return res.end();
      });
    });
  }
  res.setHeader("Content", "text/html");
  res.write("<html");
  res.write("<head><title>My First Page</title></head>");
  res.write("<body><h1>Yo, dog!</h1></body>");
  res.write("</html>");
  res.end();
});

Open in new window


This is what I understand: The order in which this code is being fired is:

req.on("end", () => { -> Event Listener is registered, but not triggered until the end of the overall process

res.setHeader("Content", "text/html"); -> this will fire before the "req.on" because while "req.on" is seen by the process, it's fired asyncronously so it's not processed until the very end.

That's going to be a problem in the the headers have already been set, which result in an error.

However, if I do this:

return req.on("end", () => { - then I don't get an error and the code runs fine.

Why? What's significant about "return" that it allows the code to run in a healthy manner? It seems like it's still and Event Listener and, as far as the Call Stack, it's not being fired until the end and I would expect the same error. But there is no error and I want to understand why.

What do you think?
Avatar of vogen gurung
vogen gurung
Flag of Australia image

In my understanding, the IF block wants to end and return when condition is met.
res.statusCode 302 tells client to look at(browser to) another url.

Code below is outside if block.
rest.setHeader("Content", "text/html");

According to HTTP status code, 302 has been superseded by  303 and 307.
I am confused about what you are wanting to achieve.

Your if statement is going to fire off the req.on('data') event handler - which will complete in an indeterminate time (async).
The statement after the if is going to execute immediately - i.e. before the data / end events complete.

Yet in these statements you are sending output which will kill any headers you send in the data / end events.

I am guessing this code should be contained in an else
  res.setHeader("Content", "text/html");
  res.write("<html");
  res.write("<head><title>My First Page</title></head>");
  res.write("<body><h1>Yo, dog!</h1></body>");
  res.write("</html>");
  res.end();

Open in new window

Based on your code you won't get here on a POST to /message because of the redirect to '/' in the end event handler which currently will not work because of the above.

As for the return - not sure which one you are referring to but the return res.end() is not really going to do anything as there is nothing looking for a response from the .on('end'...) handler.

I would recommend taking a read of this article which gives a good overview of the HTTP transaction process
https://nodejs.org/en/docs/guides/anatomy-of-an-http-transaction/
Avatar of Bruce Gust

ASKER

Gentlemen!

This is all part of a tutorial that I'm doing on Udemy. Let me give you the whole code so you can see everything that I'm looking at / trying to understand. That way, too, you can see the result of adding the "return" that I'm trying to comprehend, as far as why it makes the difference that it does.

Here's the whole code:

const http = require("http");
const fs = require("fs");

const server = http.createServer((req, res) => {
  const url = req.url;
  const method = req.method;
  if (url === "/") {
    res.write("<html");
    res.write("<head><title>My First Page</title></head>");
    res.write(
      '<body><form action="/message" method="POST"><input type="text" name="message"><button type="submit">Send</button></form></body>'
    );
    res.write("</html>");
    return res.end();
  }
  if (url === "/message" && method === "POST") {
    const body = [];
    req.on("data", chunk => {
      console.log(chunk);
      body.push(chunk);
    });
    [b] req.on("end", () => {[/b]
      const parsedBody = Buffer.concat(body).toString();
      const message = parsedBody.split("=")[1];
      fs.writeFile("message.txt", message, err => {
        res.statusCode = 302;
        res.setHeader("Location", "/");
        return res.end();
      });
    });
  }
  res.setHeader("Content", "text/html");
  res.write("<html");
  res.write("<head><title>My First Page</title></head>");
  res.write("<body><h1>Yo, dog!</h1></body>");
  res.write("</html>");
  res.end();
});

server.listen(3000);

Open in new window


That's the code in its entirety...and this is coming right from the tutorial,

The instructor rightfully acknowledges that the code in its present state will throw an error:

$ node play.js
<Buffer 6d 65 73 73 61 67 65 3d 56 69 76 69 61 6e>
_http_outgoing.js:470
    throw new ERR_HTTP_HEADERS_SENT('set');
    ^

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the cli
ent
    at ServerResponse.setHeader (_http_outgoing.js:470:11)
    at fs.writeFile.err (C:\wamp\www\adm\node\play.js:27:13)
    at FSReqWrap.oncomplete (fs.js:141:20)

Reason being is that, while the Event Listener that I have in bold is registered (I'm using that term because it's what used in the tutorial. I'm assuming that term refers to the fact that the Event Listener is throwing that functionality into the Call Stack), but it doesn't fire until the "end" of the process is reached. By that point, you can't monkey with the headers because they've already been written.

But...

If I do this:

const http = require("http");
const fs = require("fs");

const server = http.createServer((req, res) => {
  const url = req.url;
  const method = req.method;
  if (url === "/") {
    res.write("<html");
    res.write("<head><title>My First Page</title></head>");
    res.write(
      '<body><form action="/message" method="POST"><input type="text" name="message"><button type="submit">Send</button></form></body>'
    );
    res.write("</html>");
    return res.end();
  }
  if (url === "/message" && method === "POST") {
    const body = [];
    req.on("data", chunk => {
      console.log(chunk);
      body.push(chunk);
    });
    return req.on("end", () => {
      const parsedBody = Buffer.concat(body).toString();
      const message = parsedBody.split("=")[1];
      fs.writeFile("message.txt", message, err => {
        res.statusCode = 302;
        res.setHeader("Location", "/");
        return res.end();
      });
    });
  }
  res.setHeader("Content", "text/html");
  res.write("<html");
  res.write("<head><title>My First Page</title></head>");
  res.write("<body><h1>Yo, dog!</h1></body>");
  res.write("</html>");
  res.end();
});

server.listen(3000);[/code]

When I add "return" to what I have in bold, at that point, the "return" syntax acts as a quasi "die." This is the situation I was trying to understand that has since been explained by a coworker, but I'm open to any other commentary y'all might want to provide.

What I understand is that the use of "return" in the situation you see above will result in the process coming to screeching halt right after "return res.end." You won't see "Yo, dog!" at all. Plus, you won't see any server errors as far as the headers getting all jacked up.

Is that right?

By adding "return" to the beginning of "req.on("end", () => {," "Yo, dog" will never make it to the Call Stack because of the way "return" will route the flow of the page so it concludes before "Yo, dog" is ever considered.

Correct?
ASKER CERTIFIED SOLUTION
Avatar of Julian Hansen
Julian Hansen
Flag of South Africa image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thanks, guys!