Pub-Sub and Event-Driven Programming
You can see instances of event-driven programming in:
- Browser events (
- Node.js server events
- Redux and other state management libraries
- RxJS and other event libraries
- GraphQL subscriptions
There are different names for the various event design patterns, but the core concept is the same. In this lesson, we will build a Pub-Sub, but the intuition will be transferable. Other similar concepts are:
- Observer pattern
- Event bus
- Message queue
- Event-driven architecture
There are subtle differences between the different pattern implementations, but the important learning outcomes are all the same. In this question, you will build a Pub-Sub (publish-subscribe pattern) where publishers emit actions and subscribers listen for a specific action and execute a callback accordingly.
We will implement the Pub-Sub as a class with
They will communicate through an
eventName channel which is just a string.
It should be built so that many
subscribers can listen for the same event.
Then to use it, we do the following:
Our Pub-Sub implementation will give us the ability to
subscribe to an event,
publish data to an event, and a place to store the subscribed callbacks.
In the constructor, we initialized a
subscriptions object whose key-value pairs will be the event channel which maps to an array of event callbacks.
The first thing we should implement is the
The function takes an
eventName which is a string, and a
callback which is a function that executes with the data.
First we check if an array of callbacks in
subscribers already exists for the
eventName channel, and if it doesn't exist, we initialize it now.
Then we push the
callback to this array which is a function that takes a single argument.
When we want to trigger an event, we
publish under the
eventName and pass it the
data for that event.
Our callbacks should take at most one argument, but it could take no arguments if it does not use the
In our case, the
data can be anything, but you could enforce it to be something specific either in your Pub-Sub implementation or by the
callback for a specific
publish an event, we first check that the
eventName has been initialized and return early if it has not.
If it does exist, we iterate through all the
subscribers for that
eventName and execute their callbacks.
We want to allow our code to clean up a subscription and remove its listener.
We pass an
eventName and the same
callback from the
subscribe method to remove it.
Then the callback is filtered out of our
subscribers for that channel.
Interact with this solution in a REPL.
One challenge developers have with a Pub-Sub is the terminology because it makes it sound much more challenging than it actually is. When we say a subscriber is "listening", all this means is that we have a hash table (object) that has an array of events for a given key. A subscriber adds its callback to this array, and the publisher just executes all the callback under that key when it "emits" the matching event.
If you have used Redux, what's happening underneath the hood is almost the exact same.
The only difference is that we are storing state inside our Pub-Sub, and the
is passing the action to every reducer, and they decide if they should update a piece of state based on the action.
Below is a simple implementation with phrases changed to Redux terminology:
For larger system Pub-Subs, message queues, and observers, it requires more robust storage and communication channels, but the fundamentals are still the exact same. Maintain channel names and a list of functions to execute.
Table of Contents