7

I'm working on a project where I have a Feeds page which shows all type of post by all users. Type specific list page and Posts' detail page.

Pages- 1. Feeds 2. List (Type specific) 3. Detail (detail of a post)

So I have following Mongo collection - 1. Feed 2. type1 post 3. type2 post 4. type3...

Now when a user post a new Post I save it to respective collection lets say to 'type1 post' and return success to browser. But I also want to update my 'Feed' collection with same data. I don't want it to be done before response is send. Because that will increase User's wait time. Hence I have used Events. Here's my code -

const emitter = new event.EventEmitter();

function savePost(){
    //  Code to save data to Mongo collection

    emitter.emit('addToFeeds', data);
    console.log('emit done');

    return res.json(data);
}

emitter.on('addToFeeds', function(data){
    // code to save data to Feeds collection
    console.log('emitter msg - ', data);
});

Now when I check the console.log output, it shows "emitter msg -" first and then "emit done". That's why I'm assuming emitter.on code is executing before res.json(data);

Now I'm wondering does Events are blocking code? If I have to update Feeds in background or after response is sent what is the right way? In future I also want to implement caching so I also have to update cache when even a post is added, that too I want to do after response is sent or in background.

Shrikant
  • 324
  • 5
  • 17

2 Answers2

12

Yes, events are synchronous and blocking. They are implemented with simple function calls. If you look at the eventEmitter code, to send an event to all listeners, it literally just iterates through an array of listeners and calls each listener callback, one after the other.

Now I'm wondering does Events are blocking code?

Yes. In the doc for .emit(), it says this: "Synchronously calls each of the listeners registered for the event named eventName, in the order they were registered, passing the supplied arguments to each."

And, further info in the doc in this section Asynchronous vs. Synchronous where it says this:

The EventEmitter calls all listeners synchronously in the order in which they were registered. This is important to ensure the proper sequencing of events and to avoid race conditions or logic errors. When appropriate, listener functions can switch to an asynchronous mode of operation using the setImmediate() or process.nextTick() methods:

If I have to update Feeds in background or after response is sent what is the right way?

Your eventListener can schedule when it wants to actually execute its code with a setTimeout() or a setImmediate() or process.nextTick() if it wants the other listeners and other synchronous code to finish running before it does its work. So, you register a normal listener (which will get called synchronously) and then inside that, you can use a setTimeout() or setImmediate() or process.nextTick() and put the actual work inside that callback. This will delay running your code until after the current Javascript that triggered the initial event is done running.

There is no actual "background processing" in node.js for pure Javascript code. node.js is single threaded so while you're running some Javascript, no other Javascript can run. Actual background processing would have to be done either with existing asynchronous operations (that use native code to run things in the background) such as network I/O or disk I/O) or by running another process to do the work (that other process can be any type of code including another node.js process).

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • After reading your answer I came to know 2 new functions of node. I was surprised to know the we can very easily control our code to be executed in next event loop (tick). This [link](https://stackoverflow.com/a/44275063/4765206) helped me to understand difference in setImmediate and nextTick. – Shrikant May 11 '18 at 17:03
  • Keep in mind that `setImmediate()` and `process.nextTick()` allow you to change the timing of when your code runs, but it is still blocking when it runs (e.g. no other system events are processed while your code runs). Running it later keeps it from blocking the processing of the current event, but not from delaying the running of later events. – jfriend00 May 11 '18 at 17:09
  • You mean If I use these functions I can skip current event-loop (current response is send, user (browser) don't have to wait) but in next event-loop while processing the code inside setImmediate or process.nextTick() will block next request-response from browser? What if we are using Clusters, we won't fall in this situation Right? – Shrikant May 14 '18 at 10:50
  • It is worth to mention that node has "workers" that can run in separate threads (since node 10.5.0). https://nodejs.org/api/worker_threads.html. – Stephane L Aug 18 '22 at 15:31
3

Events are synchronous and will block. This is done so that you can bind events in a specific order and cascade them in that order. You can make each item asynchronous, and if you're making HTTP requests at those events, that's going to happen async, but the events themselves are started synchronously.

See: https://nodejs.org/api/events.html#events_emitter_emit_eventname_args

And: https://nodejs.org/api/events.html#events_asynchronous_vs_synchronous

Dan Crews
  • 3,067
  • 17
  • 20