Create a simple Event Bus in Javascript

Event buses are an extremely useful tool for decoupling the components of your apps. Using an event bus has pros and cons and must be done carefully, otherwise you may end up with code hard to maintain and understand.

But there’s no doubt an event bus can significantly speed up your prototyping process or improve the architecture of a small/medium application. A large application may need some extra considerations.

In this article I’m going to show how to implement a simple event bus in Javascript.


An event bus based on this example is also available as a lightweight library for the browser and Node.js. The library and its documentation is at this address.

What’s an event bus

An event bus implements the publisher/subscriber pattern. It can be used to decouple the components of an application, so that a component can react to events fired from another component without them having direct dependencies with each other. They only need to know the event bus.

Every subscriber can subscribe to a specific event. A subscriber will be notified when the event it subscribes to is published on the event bus.

A publisher can publish events on the event bus when something happens.

Event bus implementation

In this implementation a subscriber is a simple function. The function is called when the event of interest is published in the event bus.

To map an event to its subscribers a simple object can be used. The format of the data in this object will be: { eventType: { id: callback } }. For example:

{
event1: { 1: func1, 2: func2 },
event2: { 3: func3 }
}

The events event1 and event2 can be of any type. In most cases it makes sense to use simple strings.
The subscribers func1, func2 and func3 are simple Javascript functions.
func1 and func2 are subscribers, subscribed to events of type event1.
func3 is a subscriber, subscribed to events of type event2.

The IDs 1, 2 and 3 will be used later to unsubscribe subscribers.

Subscribe

The subscribe function takes as arguments the event of interest and a subscriber.

The function returns and object that exposes an unsubscribe function. The unsubscribe function can be called to remove the subscriber that has been registered.

In this example I’m using an ID generator to get unique IDs.
IDs are used to immediately identify (in O(1) time) a subscriber when calling the unsubscribe function.

I have provided a complete implementation of a very simple ID generator at the end of this article.

Instead of using an ID generator, a real implementation could consider using ES6 Symbols instead.

const subscriptions = { }
const getNextUniqueId = getIdGenerator()
function subscribe(eventType, callback) {
const id = getNextUniqueId()
// create new entry for eventType
if(!subscriptions[eventType])
subscriptions[eventType] = { }
// the callback is registered
subscriptions[eventType][id] = callback
return {
unsubscribe: () => {
delete subscriptions[eventType][id]
if(Object.keys(subscriptions[eventType]).length === 0)
delete subscriptions[eventType]
}
}
}

Publish

The publish function takes as arguments the event and the arguments for the subscribers.

If there are no subscribers for eventType, it just returns.

Otherwise it iterates over the IDs of the subscribers registered for eventType and calls each function, passing the provided arguments.

function publish(eventType, arg) {
if(!subscriptions[eventType])
return
Object.keys(subscriptions[eventType])
.forEach(id => subscriptions[eventType][id](arg))
}

Usage

As a simple example, say that we want to print something in the console each time an event of type “print” is emitted.

We can subscribe a listener like this:

const subscription = EventBus.subscribe(
"print",
message => console.log(`printing: ${message}`)
)

We can then emit an event like this:

EventBus.publish("print", "some text")

If at some point we are not interested in reacting to events of type “print” we can unsubscribe like this:

subscription.unsubscribe()

Complete implementation

Here is the complete implementation of this event bus, as a node module. It can be easily be converted to a plain Javascript function.

The code of this post is also available in this Gist and has been used as a base for this ready to use library.


Where can you find me?

Follow me on Twitter: https://twitter.com/psoffritti
My website/portfolio: pierfrancescosoffritti.com
My GitHub account: https://github.com/PierfrancescoSoffritti
My LinkedIn account: linkedin.com/in/pierfrancescosoffritti/en

Pierfrancesco Soffritti

Written by

- Software engineer @Google - WebSite: https://pierfrancescosoffritti.com - GitHub: https://github.com/PierfrancescoSoffritti

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade