Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

node.js - attaching event handlers on time

I'm studying node.js and came across this example in the node.js manual:

...
var req = http.request(options);
req.end();

req.on('upgrade', function(res, socket, upgradeHead) {
  console.log('got upgraded!');
  socket.end();
  process.exit(0);
});
...

What I see in this example is that handler attached to an event of HTTP request, after the request is created and even after it is (scheduled to be) sent. To make things even worse, manuals says:

If this event isn't being listened for, clients receiving an upgrade header will have their connections closed.

Isn't it possible for the event to occur before req.on(... had a chance to attach a handler ? I suspect I don't understand something in node's asynchronous model. Or this code from node manual designed in hope that network request will take longer than executing next line of code ?!

Another example:

http.get("http://www.google.com/index.html", function(res) {
  console.log("Got response: " + res.statusCode);
}).on('error', function(e) {
  console.log("Got error: " + e.message);
});

Here, HTTP request will be initiated immediately after the object created, and we attach an error handler only afterwards. Again, (1) is it a code that works only because of network latencies, (2) I don't get something about node.js concepts, or (2b) event will "wait" until I attach a handler to it ?

EDIT: Even better example, also from manual. Good and Bad examples below are different only because in the good one we attach the event quick enough and thus have low chances to miss data, or it is never possible to miss data this way (and why ?!)

// Good
request.on('response', function (response) {
  response.on('data', function (chunk) {
    console.log('BODY: ' + chunk);
  });
});

// Bad - misses all or part of the body
request.on('response', function (response) {
  setTimeout(function () {
    response.on('data', function (chunk) {
      console.log('BODY: ' + chunk);
    });
  }, 10);
});
like image 392
Sandman4 Avatar asked Jul 23 '12 14:07

Sandman4


People also ask

Why is that using async function with event handler is problematic?

Using async functions with event handlers is problematic, because it can lead to an unhandled rejection in case of a thrown exception: const ee = new EventEmitter(); ee. on('something', async (value) => { throw new Error('kaboom'); });

Which method attaches an event handler to an element?

The addEventListener() method attaches an event handler to the specified element. The addEventListener() method attaches an event handler to an element without overwriting existing event handlers. You can add many event handlers to one element.

Which operator is used to attach an event handler to an event?

Use the addition assignment operator ( += ) to attach an event handler to the event.


1 Answers

What you miss is that JavaScript isn't asynchronous at all! What I mean is that JavaScript is single-threaded and asynchronous operations are actually not asynochronous. There is a very fancy queue model which gives as the illusion of JavaScript being asynchronous (don't get me wrong: it still is the most efficient model).

So what does it mean? It means that once the synchronous code is running it is impossible for other code to be running parallely. So for example in this code

var req = http.request(options);
req.end();
req.on(...);

the request is scheduled, but the main thread (i.e. the operation) hasn't ended at req.end(). As long as the main operation has not finished no asynchronous code can fire in-between. In particular the handler is always set before the actual event has any chance to occure.

One more example to make it a bit clearer. Consider this code:

var http = require('http');
http.createServer(function (req, res) {
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end('Hello World\n');
    while(true) { } // <------ infinite loop doing nothing
}).listen(1337, '127.0.0.1');

Note that the first request will finish with success. But any other request will never get a response. This is because the loop will never finish the operation and JavaScript cannot jump to another event because of it. This code permamently crashes the app beyond any hope. So be careful with synchronous code with Node.js. :)

like image 136
freakish Avatar answered Oct 10 '22 00:10

freakish