Today's rabbit hole: what is Event Driven Programming and how to code your own EventEmitter
Tags: webdev, beginners, javascript, node
Published: 2020-08-30 22:03:40

_Note: this is first and foremost the tale of a journey. It acts as a how-to, but I also want to share my thought process and how I learnt along the way. If any of the below is total nonsense, let me know in the comments!_

Trigger: few months ago I was put in a situation where I was asked to build my own `EventEmitter`. I didn't have a clue and it was very embarrassing. The tale below is my quest to learn about it.

I explained it to a friend and he told me: `ah, you are supposed to build an [EventTarget](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/EventTarget)!`. Ehhhh, what the hell do you mean?!

I Googled `what is js eventemitter` and landed in [a nodejs tutorial](https://www.tutorialspoint.com/nodejs/nodejs_event_emitter.htm). 

Reading the first few lines of the article made me think about the `Javascript Event Loop`, which I have read quite a lot about it. 

#What is Javascript's Event Loop?#

At Lambda School we have a Slack channel where students can share questions they may have been asked in recent job interviews. In my growth mindset attitude and my quest to learn what really matters in the industry, I started to track these questions and read about the topics. Believe or not, the first question I tracked was `What is Javascripts Event Loop, and how does it work?`. I had done a bit of research and had settled with the following 2 articles:

1. [Flavio Copes' The JavaScript Event Loop](https://flaviocopes.com/javascript-event-loop/)
2. [Sukhjinder Arora's Understanding Asynchronous JavaScript](https://blog.bitsrc.io/understanding-asynchronous-javascript-the-event-loop-74cd408419ff)

The main idea is that Javascript is single threaded. That means that things run one after another and anything that takes time to return blocks the execution of the code. As Flavio ilustrates very well, the event loop continuously checks the `call stack` which, like any Stack, it's Last In First Out (LIFO). When it finds a function to execute, it adds it to the Stack

```
const bar = () => console.log('bar')

const baz = () => console.log('baz')

const foo = () => {
  console.log('foo')
  bar()
  baz()
}

foo()
```

^ Source: [Flavio Copes article](https://flaviocopes.com/javascript-event-loop/)

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/jzaxzc2xfq3uezzro6fr.png)

^ Source: [Flavio Copes article](https://flaviocopes.com/javascript-event-loop/)

What happens when there is async code. Flavio adds a `setTimeout()` in his code:

```
const bar = () => console.log('bar')

const baz = () => console.log('baz')

const foo = () => {
  console.log('foo')
  setTimeout(bar, 0)
  baz()
}

foo()
```
^ Source: [Flavio Copes article](https://flaviocopes.com/javascript-event-loop/)

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/u7u89ov0s87ug9ibu0p7.png)

^ Source: [Flavio Copes article](https://flaviocopes.com/javascript-event-loop/)

In this case, `setTimeOut()`, even if triggered after 0 miliseconds, is async. Browser or Node.js start a timer and, when the timer expires, the code that it needs to execute is added to something called the `Message Queue` - which sits at the bottom of the Stack. I learnt that user triggered events like mouse clicks are also added to that queue. 

ES6 introduced the `Job Queue` for `Promises`. That means that the result of a Promise (i.e. fetching data from an API) is executed as soon as possible rather than being added to the `Message Queue`. 

As I read in [here](https://www.tutorialspoint.com/nodejs/nodejs_event_loop.htm), whenever a task gets completed in the Stack, Node fires an event that signals the event-listener to execute. Event handlings is based on the `observer pattern`. The `observer pattern` is a `a software design pattern in which an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods.` (source: [Wikipedia](https://en.wikipedia.org/wiki/Observer_pattern)). The article even has code snippets in JS using... [`RxJS`](https://en.wikipedia.org/wiki/Observer_pattern#JavaScript). Oh dear, I have heard about [`RxJS`](https://github.com/ReactiveX/rxjs) quite a lot. _Putting RxJS in the parking lot for now_

#Ok man, what about the EventEmitter I was supposed to code?#

I went back to the [first](https://www.tutorialspoint.com/nodejs/nodejs_event_emitter.htm) resource I mentioned. There I read that `Many objects in a Node emit events, for example, a net.Server emits an event each time a peer connects to it, an fs.readStream emits an event when the file is opened. All objects which emit events are the instances of events.EventEmitter.`. And it goes on to explain that `EventEmitter` is a Class that lives inside the `event` [module](https://nodejs.org/api/events.html#events_class_eventemitter). 

I went straight to the example listed in the article to understand the methods. And to my surprise, it all made sense! I coded a little example and I was happy it all made sense. I am not building my own eventEmitter at this point, just practising the methods. The only doubt I had is how to pass arguments to the listeners. For instance:

- I wanted to add the name of the event to the sentence being logged:

```
const listener1 = (argument) => {
	console.log(`Hey, I am listener 1 on event ${argument}`);
};
```

I thought I would just invoke the listener with an argument in it:
```
emitter.addListener('test', listener1('test');
```

That threw an error. I Googled it and found the answer [here](https://stackoverflow.com/a/24415198/3630417): it turns out that when adding listener you are only declaring the name of the function, not invoking it. The arguments are passed when the event is emitted. Like so:

```
emitter.addListener('test', listener1);
emitter.emit('test', 'arg1');
```

What if we have several listeners that are expecting different arguments? Like so:

```
const listener1 = (arg1) => {
	console.log(`Hey, I am listener 1 on event ${arg1}`);
};

const listener2 = (arg2) => {
	console.log(`Hey, I am listener 2 on event ${arg2}`);
	return 'listener 2';
};
```

My understanding from the Stack Overflow answer above is that all arguments possibily expected by any of the listeners have to be passed, and all possible arguments need to be declared in the listener functions. Like so:

```
const listener1 = (arg1, arg2) => {
	console.log(`Hey, I am listener 1 on event ${arg1}`);
};

const listener2 = (arg1, arg2) => {
	console.log(`Hey, I am listener 2 on event ${arg2}`);
	return 'listener 2';
};
```

I actually don't need `arg2` in `listener1`, because it comes after arg1, but I definitely need it in in `listener2` otherwise `arg2` will be the first argument being passed in the `emit` method. Then I am emitting the event `test` like so:

```
emitter.emit('test', 'arg1', 'arg2');
```

It is actually explained in [here](https://nodejs.org/api/events.html#events_passing_arguments_and_this_to_listeners) but I saw it only later!

#Ok. This is what comes out of the the Node.js box. How do you build your own EventEmitter?#

This is the destination of my rabbit hole afterall! I Googled it and found the following tutorials: 

1. [How to Create Your Own Event Emitter in JavaScript by Oleh Zaporozhets](https://medium.com/better-programming/how-to-create-your-own-event-emitter-in-javascript-fbd5db2447c4)
2. [How to code your own event emitter in Node.js: a step-by-step guide by Rajesh Pillai](https://www.freecodecamp.org/news/how-to-code-your-own-event-emitter-in-node-js-a-step-by-step-guide-e13b7e7908e1/)

I had fun reading and finally learning to implement my `eventEmitter`. The key concept that I had to grasp was the following:

- An `emitter` emits one or many `events`.
- An `event` triggers one or many `listeners`. A `listener` is a call back function: a function that executes when the `event` is received. But first, you need to `add` or `register` (I think people also call is `subscribe`) the listener to the event.

So, conceptually, it makes sense to store the events in an `object` inside the `emitter`. It also makes sense to store every `listener` to an event inside an `array`. This way, when an `event` is emitted, we look up for the `event` inside the object (it is O(1)) and we then execute all the listeners stored in it in sequence (it is O(n)). I suppose that, since all listeners need to be executed, there is no way to improve O(n).

I personally always have a lot of fun working with Classes - I find OOP programming to be super logical and I have fun because everything in it is linked to each other. I know, JS is not pure OOP because it is prototype based... let's leave this for another day.

#Now, how do we build the `EventEmitter` Class?#

I found [Rajesh's article](https://www.freecodecamp.org/news/how-to-code-your-own-event-emitter-in-node-js-a-step-by-step-guide-e13b7e7908e1/) great because it builds a lot of the native Node.js `eventEmitter` methods (i.e. `listenerCount()`, `rawListeners()` etc.).

##Class##

We first build the Class constructor:

```
class EventEmitter {
	constructor() {
		this.events = {};
	}
}
```

As discussed, the `events` property will be an object and we will access the event listeners with `this.events[name]`.

##Add Listener##

Next, we create the `addListener` method. It takes two arguments: `name of the event` and `listener` (function to be executed when event is emitted):

```
addListener(name, listener) {
// if event name has not yet been recorded in the object (it is not a property of `this.events` yet), we do it and initialise an array
	if (!this.events[name]) {
		this.events[name] = [];
	}
// we push the `listener` (function) into the array
	this.events[name].push(listener);
}
```

##On##
since `.on` and `addListener` are the same, we code `.on` like that:

```
on(name, listener) {
	return this.addListener(name, listener);
}
```

##Remove Listener##

Next, we can code `removeListener()`, which is removing the listener from the array in `this.events[name]`:

```
removeListener(name, listenerToRemove) {
// if event name does not exist in `this.events` object, we throw an error because nothing can be removed
	if (!this.events[name]) {
		throw new Error(`Can't remove listener, event ${name} doesn't exist`);
	}
// we use one of the high order methods (filter) to filter out the listener to be removed from the array
	this.events[name] = this.events[name].filter((listener) => {
		return listener != listenerToRemove;
	});
}
```

##Off##

Similar to `.on`, `.off` is equivalent to `removeListener()`. So:

```
off(name, listenerToRemove) {
	return this.removeListener(name, listenerToRemove);
}
```

##Once##

Next, I learnt a lot reading how Rajeh implemented the `.once` method. `once` means that the listener will be automatically removed after it has executed once. So:

```
once(name, listener) {
// we check if event exists in the object, and if not we create an intialise an array
	if (!this.events[name]) {
		this.events[name] = [];
	}
// we create a wrapper function, which is the one that will be added to the array. This wrapper function executes the listener that we want to add and calls .removeListener
	const onceWrapper = (...arg) => {
		listener(...arg);
		this.removeListener(name, onceWrapper);
	};
// we push the wrapper function into the array
	this.events[name].push(onceWrapper);
}
```

The thing that tripped me here is that I was initially removing the listener that I wanted to add. No, I should remove the wrapper because (remember we use the method `filter` to remove listeners?) otherwise we won't find it and nothing will be removed. It took me a while to find out what I was doing wrong.

##Emit##

Next, we code `emit`. Emit has an obligatory argument (the name of the event) and then you can pass as many arguments you want to the listeners. That is why I used `...arg` above, since we don't know how many arguments will be passed ahead of time. Maybe a certain listener expects 3 (this number is just an example), and all listeners recorded for the event (added to the array) need to be prepared to receive that many arguments in case their arguments come after these 3. Unless I am wrong, you can achieve this by spreading the arguments (`...args`): 

```
emit(name, ...data) {
	if (!this.events[name]) {
		throw new Error(`Can't emit an event. Event ${name} does not exist.`);
	}

	this.events[name].forEach((cb) => {
		cb(...data);
	});
}
```

First, if `event` does not exist (no property with the `name` of the event is found inside the `this.events` object), then we throw an error. If we find the event, we iterate over the array with `forEach` and we execute the listener passing the arguments, if any. 

I have seen implementations out there that seem to have forgotten the arguments, or maybe I am missing something. In any case, mine seems to work, if you spot any mistake please let me know in the comments.

##Listener count##

Next, `listenerCount`. It takes one argument (the name of the event) and returns the count of listeners (the ones stored in the array). I think the code is self explanatory:

```
listenerCount(name) {
	if (!this.events[name]) {
		this.events[name] = [];
	}
	return this.events[name].length;
}
```

##Raw Listeners##

The last one I coded is `rawListeners`, which return an array of the listeners that have been registered to an event. While this had the most misteriours name to me, it's the easiest of all afterall - it just needs to return the array.

```
rawListeners(name) {
	return this.listeners[name];
}
```

And that is it: you can now instantiate your new `EventEmitter` class and run the methods on this instance:

```
const myEmitter = new EventEmitter();
myEmitter.on('testEvent', handler1);
myEmitter.on('testEvent2', handler1);
myEmitter.emit('testEvent', 'hey there');
myEmitter.emit('testEvent', 'firing event again');
myEmitter.emit('testEvent', 'and again');

etc.
```

Hope you enjoyed it! If you spot any mistakes, let me know in the comments.