2

Node.js approach is event driven and I was wondering how would you tackle the problem of when to fire off an event?

Lets say that we have some actions on a web application: create some data, serve pages, receive data etc.

How would you lay out these events? In a threaded system the design is rather "simple". You dedicated threads to specific set of tasks and you go down the road of thread synchronization. While these task are at low on demand the threads sit idle and do nothing. When they are needed they run their code. While this road has issues it's well documented and kind of solved.

I find it hard to wrap my head around the node.js event way of doing things. I have 10 request coming in, but I haven't created any data so I can't serve anying, creating data is a long action and another 5 client wants to send data. What now?

I've created the following untested code which is basically a pile of callbacks which get registered and should be executed. There will be some kind of a pile manager that will run and decide which code does it want to execute now. All the callback created by that callback can be added "naturally" to the even loop. It should also register it's self so the event loop could give the control back to it. Other things like static content and what ever can be bound differently.

  1. How can I register a call back to be the last call in the current event loop state?
  2. Is this a good way to solve this issue?
Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
qballer
  • 2,033
  • 2
  • 22
  • 40
  • You may want to check out this [other answer](https://stackoverflow.com/a/49678428/697630) which seems to be about the same thing, from a different angle. – Edwin Dalorzo Apr 07 '19 at 13:55
  • 1
    But to summarize it: Compare it to how your hardware architecture works. Your processor is way faster than your hard drive, when you want to read a file, the OS registers a interruption to be notified when data is available in the disk buffer, and in the mean time, it goes and do something else. The CPU is always busy. When the disk buffer has data available an interruption is generated and the OS then can dedicate some CPU for it. So, there was never a thread waiting. That's the same principle in NIO. The code never blocks a thread. When there's work to do, a thread will be assigned to do it. – Edwin Dalorzo Apr 07 '19 at 14:44

2 Answers2

3

The most important thing to remember when coming from a threaded environment is that in node you don't wait for an action to finish happening, instead you tell it what to do when it is done. To do this you use a callback, this is a variable which contains a function to execute, or a pointer to a function if you like.

For example:

 app.get('/details/:id?', function (req, res) {
    var id = req.params.ucid,
        publish = function (data) {
            res.send(data);
        };
    service.getDetails(id, publish);
});

You can then invoke the publish method from within your get details method once you have created the required data.

getDetail : function (id, callback) {
    var data = makeMyData(id);
    callback(data)
}

Which will then publish your data back to the response object. Because of the event loop node will continue to serve requests to this url without interrupting the data generation from the first request

Mark Taylor
  • 122
  • 1
  • 7
  • So because you register a call back and not return a value from a function you are actually letting the event loop handle it? doesn't callback(data) gets compute on the spot? – qballer Aug 09 '12 at 14:15
  • You are correct callback(data) would get called on the spot, it was a bad example from me I am afraid. If you are performing lengthy I/O operations you would be better off using an event emitter. Once the I/O or data generation operation was complete it would then emit a complete event which could contain the callback with the filled out data. For more information on event emitters see [link](http://nodejs.org/api/events.html) – Mark Taylor Aug 09 '12 at 15:10
  • You can always refactor your answer. – qballer Aug 09 '12 at 15:18
  • Sorry while this answer is great, it's still wrong so I've unaccepted it. – qballer Aug 19 '12 at 11:49
0

The answer chosen is the most correct, there is but one minor code change and that is:

Change this function from this:

getDetail : function (id, callback) {
    var data = makeMyData(id);
    callback(data)
}

To that:

getDetail : function (id, callback) {
    var data = makeMyData(id);
    setTimeout(callback, 0, data); 
}

Update 2019: In order to comply with community standard I've broken off an update to a new answer. I've used setTimeout because I wanted to defer the callback to the back of the event loop. Another option I've used was process.nextTick(), this helped to defer the callback to the end of the current event processed. For example:

getDetail : function (id, callback) {
    var data = makeMyData(id);
    process.nextTick(((info)=> callback(info))(data)) 
}
qballer
  • 2,033
  • 2
  • 22
  • 40