2

I am confused about some terms. I am trying to find out how the event system of Node.js actually works, and in a lot of places I read that the event handlers are totally synchronous.

For me that seemed really strange, because one of the advantages of using an event-driven approach would be that the main thread would not be blocked by events. So I tried to come up with my own example, and it seems like that what did happen was what I actually expected:

const fs = require('fs')
const util = require('util')
const readFile = util.promisify(fs.readFile)

const events = require('events')
const emitter = new events.EventEmitter()

emitter.on('fire', () => {
  readFile('bigFile.txt')
    .then(() => console.log('Done reading bigFile.txt'))
    .catch(error => console.log(error))
  console.log('Sync thing in handler')
})

emitter.on('fire', () => {
  console.log('Second handler')
})

console.log('First outside')
emitter.emit('fire')
console.log('Last outside')

Note that bigFile.txt is an actually large text file, processing it takes a few hundred milliseconds on my machine.

Here I first log out 'First outside' synchronously. Then I raise the event which starts the event handling process. The event handler does seem to be asynchronous, because even though we first log out the synchronous 'Sync thing in handler' text, we start using the thread pool in the background to return back with the result of reading the file later. After running the first handler, the second handler runs printing out its message, and finally we print out the last sync message, 'Last outside'.

So I started with trying to prove what some people say, which is that event handlers are by nature synchronous, and then I found them to be asynchronous. My best guess is that either people saying that the event system is synchronous mean something else, or that I have some conceptual misunderstanding. Please help me understand this issue!

szeb
  • 326
  • 3
  • 20
  • 1
    Mostly, it means that only one bit of code is ever running at any given time. If you have some long-running, purely synchronous code, event handlers won't run until it's done. In the same way, two event handlers won't run simultaneously. – Ouroborus Nov 27 '20 at 20:16
  • 2
    Where exactly did you read this? Please link the source, maybe we can clarify what it is saying. – Bergi Nov 27 '20 at 20:18
  • 1
    You can always fire an event asynchronously if you want which is sometimes done to let the stack unwind before the event fires. – jfriend00 Nov 27 '20 at 22:39
  • 1
    Thank you for the comments. @Ivar I already understood what the answer to that question says, I was confused because I thought that the handlers by definition force some kind of synchronous way of operation for some unkown reason. – szeb Nov 28 '20 at 18:07
  • @Bergi what I originally read (https://stackoverflow.com/questions/15924014/asynchronous-or-synchronous-calling-of-event-handlers-in-javascript) seems to about that the handlers are started synchronously, but they might start async things, but for me the actual wording of the answers did not clarify things. – szeb Nov 28 '20 at 18:07
  • 1
    @szeb Ah, that's specifically about DOM event handlers though, which are yet another different animal :-) – Bergi Nov 28 '20 at 18:38

1 Answers1

2

The EventEmitter class is synchronous in regard to the emit function: event handlers are called synchronously from within the .emit() call, as you've demonstrated with the fire event you fired yourself.

In general, events that come from the operating system (file and network operations, timers etc) through node's event loop are fired asynchronously. You're not firing them yourself, some native API does fire them. When you listen to these events, you can be sure that they will occur not before the next tick.

The event handler does seem to be asynchronous, because even though we first log out the synchronous 'Sync thing in handler' text, we start using the thread pool in the background to return back with the result of reading the file later

Yes, you are calling the asynchronous function readFile (that will notify you later), but that doesn't make your event listener function or the .emit('fire') call asynchronous. Even "asynchronous functions" that start a background process will immediately (synchronously) return something - often nothing (undefined) or a promise.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375