Implementing a Messaging Service in Plain JavaScript

Piero De Tomi
5 min readJan 4, 2023

--

Introduction

In 2020 talking about “plain JavaScript” may sound weird. We have TypeScript and we have a lot of libraries and excellent frameworks such as Angular, React and so on.

But truth is that from time to time, as a professional software engineer, you’ll find yourself working on a legacy web application that doesn’t use any framework on the frontend side. The only friendly-looking thing you’ll find (sometimes) will be jQuery. That’s it.

However you’ll still have to implement a good solution, hopefully structuring frontend in components, decoupling frontend from backend, writing JS modules to function as sort of view-models for your UI components. And while doing this you’ll need to use some sort of “communication protocol” to make these components work together well and talk each other.

I’ve recently been in this situation and one of the first things I did was implementing a Messaging Service JavaScript module to handle communication between components implementing the Messaging Pattern, more specifically the publish/subscribe messaging pattern.

In this article I’ll show you the (very simple) code and I’ll explain how it works and the choices I made.

GitHub Repository

If you need the ready-made solution and you prefer to inspect the code by yourself, here’s the GitHub repository with the code: feel free to use it as you like.

You’ll find the module’s source code in the ./services/messaging-service.js file.

The Messaging Service Module

To build a basic messaging service we need at least three main functions:

  • Subscribe
  • Publish
  • [Optional] Unsubscribe

The Subscribe Function

This is the function that components will call to register themselves to be notified whenever a specific topic will be published.
In order to register, components need to provide information on:

  • Who they are
  • The topic they’re interested in
  • What they’re going to do when something will be published about the topic

The Subscribe function could look something like this:

var subscriptions = [];

function subscribe (target, topic, callback) {
if (hasSubscription(target))
return;

subscriptions.push({
target,
topic,
callback
});
}

function hasSubscription (target) {
var found = false;

for (var i = 0; i < subscriptions.length; i++) {
var subscription = subscriptions[i];

if (subscription.target === target && subscription.topic === topic) {
found = true;
break;
}
}

return found;
}

When this function is called we create an object (we’ll call it subscription object) and store it inside the subscriptions array variable for later use (line 7).

The purpose of the target parameter is to identify who is subscribing to the topic.
The topic parameter is the topic we’re subscribing to.
The callback parameter should be a delegate function that will be called when something will be published about that topic.

Finally, before creating the subscription object we check and make sure that we don’t already have a subscription for the same target/topic couple (line 4).
This check will avoid ending with duplicate subscriptions at runtime (and hence duplicate callback calls), although this should be ensured by writing the application code correctly (so you might want to disable this check if you WANT your application to behave badly in case of programming errors on this aspect).

The Publish Function

This is the function that components will call to publish something about a specific topic.
In order to use this function, components need to provide information on:

  • The topic about which they’re publishing
  • What they’re actually publishing (usually information/data)

The Publish function could look something like this:

function publish (topic, payload) {
if (!payload)
payload = null;

for (var i = 0; i < subscriptions.length; i++) {
var subscription = subscriptions[i];

if (subscription.topic === topic)
subscription.callback(payload);
}
}

What is happening here is quite simple: when the publish function is called, the messaging service checks internally for any subscriptions (line 5) on the requested topic (line 8), and for each subscription that’s matching it calls the related callback, passing as parameter whatever is contained in the payload input parameter.

This way, every component subscribed to that topic will be passively notified and will do something (= whatever is inside the callback function), without even knowing who published the update on the topic: in fact they don’t care and they don’t need to know who published the update (= decoupling).

The Unsubscribe Function

This maybe considered as a bonus function. Its purpose, as you may think, is to allow a component to unsubscribe from a topic, in order to stop receiving topic updates.

The code is symmetrical to the subscribe function and looks like this:

function unsubscribe (target, topic) {
for (var i = subscriptions.length - 1; i >= 0; i--) {
var subscription = subscriptions[i];

if (subscription.target === target && subscription.topic === topic)
subscriptions.splice(i, 1);
}
}

Here we’re simply removing any subscription object matching the provided target and topic parameters.

Sample Code

I prepared a GitHub repository with the messaging service code along with some sample code that demonstrates a possible use-case.

You can find the module’s source code in the ./services/messaging-service.js file.

Using npm (after executing npm install in the root project directory), you can run the sample code executing the following command:

http-server -p [PORT]

PORT should be whatever port you would like to start the local http server on.

Then loading the page http://localhost:[PORT]/index.html you’ll see the sample page:

Now, as the quick tip suggests, if you click the “Change Name” button the name Jack Jones will change (I’ll leave the surprise of the result to you).

I know, it’s a super simple example, but it’s purpose is just to demonstrate how to practically use the messaging service: it’s up to you to leverage its full potential in a real web application.

Conclusion

Messaging is a simple but effective way to allow inter-component communication, maintaining separation/decoupling and allowing for cleaner code.

If you need to use the full code, don’t forget to head to the GitHub repository, where you can find the complete source file.

I hope this can be helpful for you!

--

--

Piero De Tomi
Piero De Tomi

Written by Piero De Tomi

I’m a software architect based in Trieste, Italy.

No responses yet