Intro to Observer Pattern in Node with Events
So the next topic we will be talking about is called event emitters, or just simply events. So first of all, who really, really likes and understands callbacks?
Okay, so maybe a few person really do understand them, and so do I, but what happens when you end up in the callback hell? There's even a website, it's called callbackhell.com. So basically, when you have a lot of nested callbacks, it becomes really, really hard to reason about the code and what is actually happening, especially when you have a lot of code in the middle. In the other callbacks above your inner callback.
So, unfortunately, just the callbacks by themselves, they're not very scaleable in terms of increasing your code size and in terms of increasing your team size. And this is how I feel sometimes when I'm working with deeply nested callbacks. It just goes deeper and deeper into the loop.
So the solution, which natively present in the node.js platform, it's called events or event emitters. The full, proper official name. So the reason why events are important to know about and to know how to use, is that they are present in pretty much all the core modules. So when you work with core modules, and even npm modules, it's very good to know how events are working. And then, when you're creating your own system, obviously you can use the same patterns.
Promises, generators, async/await, they're not solving exactly the same problems as events solve, and I will explain it later to you. And with promises and async/await, you still use callbacks, but you use callbacks in a different manner. So with events, we're still using callbacks, but now we have more power, and I will show it to you on the example.
So in a nutshell, events are, node.js observer a pattern. We have observers, also know as event listeners, on the subject. Subject, that's typically a class or an object. And then we have multiple event triggers. So we can have multiple event listeners and multiple event triggers. This is an example of how we can create a subject. So events = require events, that would be our subject, and events is a core module, so we don't need to install it with npm, it's already available as a part of the platform. And then emitter, that's the instance of a subject. That's the actual object that you create from that class. And once we do that, this emitter, this subject will magically start having properties like ".on". So ".on", it's one of the ways to define an event listener or an observer.
The way we do it, the first argument is a string, that would be the name of the event. For example, done, D-O-N-E, and the second argument would be the function. And you can argue that it's still a callback. Yes. Exactly. It's a callback, but now we can have more functionality to it because we using the callback inside of the event emitter.
Event listener, to be more precise. Let's take a look at this example. So we have not just one event listener, but two. And yeah, they're using the same name, knock, but that's actually to illustrate my point. The order in which the event listeners will be executed is the order in which those event listeners are defined.
So first, we'll see who is there, and then we will see it go away when we trigger the event with emitter.emit('knock'). So one advantage over just plain callbacks is that we can have multiple pieces of code. So in this example, we have two event listeners. With callbacks, typically you have just one piece of code, and typically you execute it at the end. With event emitters, you can execute that code anywhere you want. In the middle, in the end, multiple times, just one time, etc. So we get more benefit by using event emitters and callbacks, compared to just using the callbacks.