{"id":284463,"date":"2019-03-25T18:07:19","date_gmt":"2019-03-26T01:07:19","guid":{"rendered":"http:\/\/css-tricks.com\/?p=284463"},"modified":"2021-12-13T07:58:36","modified_gmt":"2021-12-13T15:58:36","slug":"understanding-event-emitters","status":"publish","type":"post","link":"https:\/\/css-tricks.com\/understanding-event-emitters\/","title":{"rendered":"Understanding Event Emitters"},"content":{"rendered":"\n

Consider, a DOM Event:<\/p>\n\n\n\n

const button = document.querySelector(\"button\");\n\nbutton.addEventListener(\"click\", (event) => \/* do something with the event *\/)<\/code><\/pre>\n\n\n\n

We added a listener to a button click. We\u2019ve subscribed<\/em> to an event being emitted<\/em> and we fire a callback when it does. Every time we click that button, that event is emitted and our callback fires with the event.<\/p>\n\n\n\n

There may be times you want to fire a custom event when you\u2019re working in an existing codebase. Not specifically a DOM event like clicking a button, but let’s say you want to emit an event based on some other trigger and have an event respond. We need a custom event emitter<\/em> to do that.<\/p>\n\n\n\n

An event emitter is a pattern that listens to a named event, fires a callback, then emits that event with a value. Sometimes this is referred to as a “pub\/sub” model, or listener. It’s referring to the same thing.<\/p>\n\n\n\n\n\n\n\n

In JavaScript, an implementation of it might work like this:<\/p>\n\n\n\n

let n = 0;\nconst event = new EventEmitter();\n\nevent.subscribe(\"THUNDER_ON_THE_MOUNTAIN\", value => (n = value));\n\nevent.emit(\"THUNDER_ON_THE_MOUNTAIN\", 18);\n\n\/\/ n: 18\n\nevent.emit(\"THUNDER_ON_THE_MOUNTAIN\", 5);\n\n\/\/ n: 5<\/code><\/pre>\n\n\n\n

In this example, we\u2019ve subscribed to an event called \u201cTHUNDER_ON_THE_MOUNTAIN\u201d<\/code> and when that event is emitted our callback value => (n = value)<\/code> will be fired. To emit that event, we call emit()<\/code>.<\/p>\n\n\n\n

This is useful when working with async code and a value needs to be updated somewhere that isn’t co-located with the current module.<\/p>\n\n\n\n

A really macro-level example of this is React Redux<\/a>. Redux needs a way to externally share that its internal store has updated so that React knows those values have changed, allowing it to call setState()<\/code> and re-render the UI. This happens through an event emitter. The Redux store has a subscribe function, and it takes a callback that provides the new store and, in that function, calls React Redux’s <\/code> component, which calls setState()<\/code> with the new store value. You can look through the whole implementation here<\/a>.<\/p>\n\n\n\n

Now we have two different parts of our application: the React UI and the Redux store. Neither one can tell the other about events that have been fired.<\/p>\n\n\n

Implementation<\/h3>\n\n\n

Let’s look at building a simple event emitter. We’ll use a class, and in that class, track the events:<\/p>\n\n\n\n

class EventEmitter {\n  public events: Events;\n  constructor(events?: Events) {\n    this.events = events || {};\n  }\n}<\/code><\/pre>\n\n\n

Events<\/h4>\n\n\n

We’ll define our events<\/strong> interface. We will store a plain object, where each key will be the named event and its respective value being an array of the callback functions.<\/p>\n\n\n\n

interface Events {\n  [key: string]: Function[];\n}\n\n\/**\n{\n  \"event\": [fn],\n  \"event_two\": [fn]\n}\n*\/<\/code><\/pre>\n\n\n\n

We’re using an array because there could be more than one subscriber for each event. Imagine the number of times you’d call element.addEventLister(\"click\")<\/code> in an application… probably more than once.<\/p>\n\n\n

Subscribe<\/h4>\n\n\n

Now we need to deal with subscribing<\/strong> to a named event. In our simple example, the subscribe()<\/code> function takes two parameters: a name and a callback to fire.<\/p>\n\n\n\n

event.subscribe(\"named event\", value => value);<\/code><\/pre>\n\n\n\n

Let’s define that method so our class can take those two parameters. All we’ll do with those values is attach them to the this.events<\/code> we’re tracking internally in our class.<\/p>\n\n\n\n

class EventEmitter {\n  public events: Events;\n  constructor(events?: Events) {\n    this.events = events || {};\n  }\n\n  public subscribe(name: string, cb: Function) {\n    (this.events[name] || (this.events[name] = [])).push(cb);\n  }\n}<\/code><\/pre>\n\n\n

Emit<\/h4>\n\n\n

Now we can subscribe to events. Next up, we need to fire those callbacks when a new event emits. When it happen, we’ll use event name we’re storing (emit(\"event\")<\/code>) and any value we want to pass with the callback (emit(\"event\", value)<\/code>). Honestly, we don’t want to assume anything about those values. We’ll simply pass any parameter to the callback after the first one.<\/p>\n\n\n\n

class EventEmitter {\n  public events: Events;\n  constructor(events?: Events) {\n    this.events = events || {};\n  }\n\n  public subscribe(name: string, cb: Function) {\n    (this.events[name] || (this.events[name] = [])).push(cb);\n  }\n\n  public emit(name: string, ...args: any[]): void {\n    (this.events[name] || []).forEach(fn => fn(...args));\n  }\n}<\/code><\/pre>\n\n\n\n

Since we know which event we’re looking to emit, we can look it up using JavaScript’s object bracket syntax (i.e. this.events[name]<\/code>). This gives us the array of callbacks that have been stored so we can iterate through each one and apply all of the values we’re passing along.<\/p>\n\n\n

Unsubscribing<\/h4>\n\n\n

We’ve got the main pieces solved so far. We can subscribe to an event and emit that event. That’s the big stuff.<\/p>\n\n\n\n

Now we need to be able to unsubscribe<\/strong> from an event.<\/p>\n\n\n\n

We already have the name of the event and the callback in the subscribe()<\/code> function. Since we could have many subscribers to any one event, we’ll want to remove callbacks individually:<\/p>\n\n\n\n

subscribe(name: string, cb: Function) {\n  (this.events[name] || (this.events[name] = [])).push(cb);\n\n  return {\n    unsubscribe: () =>\n      this.events[name] && this.events[name].splice(this.events[name].indexOf(cb) >>> 0, 1)\n  };\n}<\/code><\/pre>\n\n\n\n

This returns an object with an unsubscribe<\/code> method. We use an arrow function (() =><\/code>) to get the scope of this parameters that are passed to the parent of the object. In this function, we’ll find the index of the callback we passed to the parent and use the bitwise operator (>>><\/code>). The bitwise operator has a long and complicated history (which you can read all about<\/a>). Using one here ensures we’ll always get a real number every time we call splice()<\/code> on our array of callbacks, even if indexOf()<\/code> doesn’t return a number.<\/p>\n\n\n\n

Anyway, it’s available to us and we can use it like this:<\/p>\n\n\n\n

const subscription = event.subscribe(\"event\", value => value);\n\nsubscription.unsubscribe();<\/code><\/pre>\n\n\n\n

Now we’re out of that particular subscription while all other subscriptions can keep chugging along.<\/p>\n\n\n

All Together Now!<\/h3>\n\n\n

Sometimes it helps to put all the little pieces we’ve discussed together to see how they relate to one another.<\/p>\n\n\n\n

interface Events {\n  [key: string]: Function[];\n}\n\nexport class EventEmitter {\n  public events: Events;\n  constructor(events?: Events) {\n    this.events = events || {};\n  }\n\n  public subscribe(name: string, cb: Function) {\n    (this.events[name] || (this.events[name] = [])).push(cb);\n\n    return {\n      unsubscribe: () =>\n        this.events[name] && this.events[name].splice(this.events[name].indexOf(cb) >>> 0, 1)\n    };\n  }\n\n  public emit(name: string, ...args: any[]): void {\n    (this.events[name] || []).forEach(fn => fn(...args));\n  }\n}<\/code><\/pre>\n\n\n

Demo<\/h3>\n\n\n