The publish-subscribe pattern is a fundamental design pattern in JavaScript, facilitating decoupled communication between publishers and subscribers through an intermediary dispatch center.
Abstract
The publish-subscribe pattern is highlighted as the most prevalent design pattern in front-end JavaScript development. It allows for a clean separation of concerns by enabling publishers, such as a weather station, to issue notifications without needing to know about the subscribers, like building sites or ships, which can independently react to these notifications. The pattern is exemplified through a weather forecast system where the station issues warnings, and various entities respond accordingly. The conventional approach, where the weather station directly notifies each subscriber, is shown to have drawbacks such as tight coupling, violation of the single responsibility principle, and difficulty in scaling with new subscribers. The publish-subscribe pattern overcomes these issues by introducing a dispatch center or event bus that manages subscriptions and event triggers, promoting loose coupling, adherence to the single responsibility principle, and easier extensibility for new subscribers. The article further discusses the optimization of the dispatch center to handle multiple event types, reinforcing the pattern's flexibility and utility in practical applications.
Opinions
The author suggests that the publish-subscribe pattern is superior to the conventional approach of direct notification, particularly for projects with evolving requirements.
Direct notification methods are deemed acceptable only for projects with static requirements that are unlikely to change.
The pattern is praised for adhering to the single responsibility principle, which keeps the publisher (e.g., weather station) focused solely on issuing notifications.
The pattern is also lauded for reducing coupling between components, which enhances maintainability and scalability.
The author emphasizes the pattern's alignment with the open-closed principle, allowing the system to accommodate new subscribers without altering existing code.
The article advocates for the pattern's real-world applicability by drawing parallels to how content creators like the author notify followers on platforms like Medium.
The optimization of the dispatch center to handle various event types is presented as a practical enhancement, showcasing the pattern's adaptability to complex event management scenarios.
Publish-Subscribe Pattern: The Most Used Patterns in JavaScript
The publish-subscribe pattern is the most commonly used design pattern in front-end development. Yes, the most.
The typical usage scenario for this pattern is as follows:
This is actually a basic use case of the publish-subscribe pattern, and I believe you must have written some similar code.
Here, let’s learn this pattern in detail.
A Weather Forecast System
For example, now we have a weather forecast system: the weather station will issue weather warnings when extreme weather occurs. Building sites, ships, and tourists will adjust their schedules based on weather data.
Once the weather station issues a weather warning, they will do the following things:
Building site: stop work
Ships: mooring
Tourists: cancel the trip
If you were asked to write code that could be used to notify a weather warning, what would you do?
Here is a code template to simulate these objects and actions:
Normal Solution
The more intuitive and conventional way of writing is to notify each subscriber directly in the weatherWarning method and call their methods.
Did you write code like this?
Disadvantages of Normal Solution
If the requirement of your project is fixed and will never adjust in the future, this solution is okay.
However, the requirements of our project are constantly changing, which requires us to modify our code always. At this moment, this solution has some disadvantages.
1. The weather station is not independent
The weather station was supposed to focus on the weather itself, but now it needs to directly dispatch building sites, ships, tourists, and other individuals, losing independence and not complying with the single responsibility principle.
2. The coupling is too high
Building sites, ships, and tourists were supposed to be independent of each other, but they are now placed in the same function.
If one of the objects has a bug, it may cause the other objects to not work. Obviously, this is unreasonable.
3. Hard to update
If there are new objects that need to subscribe to weather information, now we can only modify the weatherWarning function.
For example, 🐌 also wants to know the weather forecast. If there is a weather warning, go home immediately.
Then we need to break the weatherWarning function and insert some code:
This violates the open-closed principle.
Analysis
We analyzed the disadvantages of the previous code, so what is the better solution?
Let’s look at a real-life case first.
I, bytefish, am a content creator. Meanwhile, I have 3000 followers on Medium. (Thanks to all of you guys.)
My followers want to know my Medium dynamic, and I also want my followers to know in time after I publish an article.
So how should I notify these 3000 followers after I publish an article?
One way is to email my followers one by one every time I publish an article. But this method is too inefficient.
The real solution is: After I click the Publish button, Medium knows about this event, and it will notify my followers.
There is an important role here: Medium, which exists as a dispatch center.
I just need to focus on writing, and then hit Publish .
And readers just need to follow my account.
Then readers can be notified in a timely after I publish an article.
Back to our weather system, the principle is the same, we need to have an intermediate scheduling system or event center. In this way, the weather station can focus on publishing weather conditions, and each unit can also directly subscribe to this event center.
Such a system can solve those disadvantages of conventional methods.
Use Publish-Subscribe Pattern
According to our analysis above, we now need to introduce a dispatch center. But this dispatch center does not exist naturally, we also need to implement it.
This dispatch center can accept user subscriptions, such as buildingsites, ships, so it should have an on method.
At the same time, the dispatch center can allow the weather station to issue warnings, and there should be a trigger method.
At the same time, we need a callback function list inside the dispatch center to store the callback functions of subscribers.
The final code is like this:
Usage:
Yes, it works!
This solution is the publish-subscribe pattern.
With this solution:
The weather station is independent, it does not need to know subscribers.
Subscribers are separate. Even if one of them fails, it will not affect the others
If there is a new subscriber, it can directly subscribe EventEmit. We don’t need to modify the existing function. We just need to add a new line code eventEmit.on(newSubscriber.doSomething()
Optimization
Before, we implemented a dispatch center for weather warnings, but this dispatch center can only dispatch weather warning events.
But in practical applications, we may need to schedule many events. For example, a button on a page can have click events, mousehover events, resize events, etc.
In order to extend the functions of our dispatch center, we can maintain a Map type data structure in the dispatch center, called Events, instead of a simple list of callback functions.
The key of Events is the type of events, and the value is the list of callback functions corresponding to this type of events.
{ eventType1: callbacks1
eventType2: callbacks2
}
The new EventEmit:
Usage:
let eventEmit = new EventEmit()
eventEmit.on('click', function () {
console.log('click the button')
})
eventEmit.on('click', function () {
console.log('click the button again')
})
eventEmit.on('resize', function () {
console.log('resize the button')
})
The formal definition of publish-subscribe pattern:
In software architecture, publish–subscribe is a messaging pattern where senders of messages, called publishers, do not program the messages to be sent directly to specific receivers, called subscribers, but instead categorize published messages into classes without knowledge of which subscribers, if any, there may be. Similarly, subscribers express interest in one or more classes and only receive messages that are of interest, without knowledge of which publishers, if any, there are.
To put it bluntly, the publish-subscribe pattern has three main roles: a publisher, some subscribers, and a dispatch center. Publishers publish messages to the dispatch center, and subscribers receive notifications from the dispatch center. This structure allows the decoupling of publishers and dispatch groups.