The Observer Pattern in JavaScript — the Key to a Reactive Behavior

A closer look at one of my favorite design patterns and why it’s so relevant in today’s reactive world

Fernando Doglio
Bits and Pieces
Published in
7 min readSep 23, 2021

--

Image by Richard Cejas from Pixabay

Many new developers tend to add a veil of magic in front of frameworks such as React because of the way they see the data flow going, and how different it is from everything they ever learned while becoming a new developer.

And it’s true, it is like magic if you don’t know what’s going on, but like Arthur C. Clarke once said:

Any sufficiently advanced technology is indistinguishable from magic

So let’s take a closer look at the basic principle behind any reactive behavior you might find in the wild and why it’s (a) not magic, and (b) so useful to understand.

Mind you, I’m not going to pretend and oversimplifying React to a single pattern is going to let you understand how the entire framework works. I’m just talking about a single principle that can be used across multiple use cases, one of them being front-end frameworks.

The Observer Pattern Explained

Let’s start at the beginning: the first thing you need to understand, is the pattern itself.

And trust me, once you do, you’ll see there is no magic, at all (sorry to burst your bubble!).

This is what is known as a “behavioral pattern” in the sense that it deals with the behavior of objects and how they interact with each other when something happens.

That being said, the pattern shows how to structure an observer-observed type of relationship when a set of objects (the observers) are interested in any type of change in the state of another, single object (the observed).

The key here though, is that the “observers” are not actively watching the observed object, instead they’re subscribing to get notified and they’re letting the observed element notify them once something happens.

And that little detail is crucial, because if you’re actively watching it means you have to spend computational cycles performing some kind of check. And while this might not look like a big thing for a single object, if you scale up to hundreds (or potentially thousands) of observers, the time required becomes significant. So yes, it’s a problem.

If instead, those observers are free to keep on working, or even just lay idle while waiting without spending processing cycles, then the pattern becomes a performance dream.

If you’re still struggling, think about it like going yourself to get your daily newspaper vs subscribing to it and getting it delivered on your doorstep. You’ll spend a lot more energy and time going there every day instead of waiting for them to deliver it to you.

The above diagram is not an attempt at a UML of the pattern (I’m looking at you purists!),but rather a simple example of how 3 observers would interact with the observed object. It’s that simple. You can see how from outside each observer would call the addSubscriber method, and how the notifySubscribers method would then call upon their update method, with a specific event parameter. The even is nothing but the details of what just changed. You could change this and instead let the observers access the observed object’s state directly, but I think this way it’s a lot easier since you’re specifically showing them what changed (i.e what triggered the notification).

You can now begin to see that there is no real magic behind this pattern, it’s just so elegant that from the PoV of the observer (which in some situations is where the developer is standing) it looks like magic.

Implementing the Observer Pattern in JavaScript

Let’s get our hands dirty now with some code!

For this example, I’m going to pretend we have some kind of loop where we’re iterating the value of a variable and we wanted to react when the value meets certain criteria.

For example, imagine having a loop from 1 to 1000 and wanting to make sure we react on every odd number. Following what I’ve been saying so far, you’d end up with something like this:

Now, we’re dealing with JavaScript here, so we have to remember that there is no concept (not yet at least) of “private” methods or properties, or even of abstract classes or methods. So we’ll have to play it by ear when implementing them.

However, we can implement something that would let us work like this:

Very straightforward implementation, but you get the point. The Lopper class will take the start and end of the loop and it’ll run it with the run method. And before that we can insert as many observers as we want through the addObserver method. The logic required to understand WHEN and HOW the observer will react is encapsulated inside each observer (in this case, OddNotifier ).

Running this code would yield an output like the following:

As you can see, we’ve implemented a very annoying observer.

So let’s take a look at that logic now:

As you can see, we’ve re-implemented the eventIsRelevant and reactToEvent methods that were also defined (as per our UML diagram) on the Observer parent class. Here we’re clearly checking the name of the event and the value. If it matches our criteria, we return true. Notice though how we’re not implementing the update method here. That’s not going to need to be overwritten, since a basic implementation as part of the parent class is going to be enough. The parent class will take care of calling the reactToEvent if appropriate. Let’s take a quick look at that now:

Nothing too fancy here, I’ve defined a very simple update method that receives an event, and if it’s relevant, it’ll react to it. Whatever that means is left to each concrete observer to define (as we’ve already seen).

As for the subject of our attention, our Looper class, it’ll take care of iterating over the values — as its very complicated logic dictates — and every time a new event needs to be triggered, it’ll notify the observers. Take a look:

The code is not concerned about how to add new observers or what it means to notify them. It only needs to know there is a method called notifyObservers and that it needs to be called on every relevant event. In this case that translates to “on every new value of my loop”. But it could be anything else really. In fact, if the logic were more complex, we could also have multiple events being triggered and depending on the logic inside each concrete observer, they would be able to decide if the event was relevant or not to them.

Finally, the Subject class is very simple, since it only needs to worry about collecting and notifying observers:

It doesn’t get simpler than that to be honest.

Now, let’s go a bit further, and try to show an example that would hit a bit closer to home, especially if you’re a React developer.

Imagine if you could do something like this:

I’ve created a “hook”, that sets the initial state of our variable looper to 1, and returns also a function to increase it by 1 every time. Other than our ability to increase our internal looper’s state by 1, do you think I have everything I need for this “magic” to work?

Because it does work:

Here is our hook implemented:

Not too strange now that we understand the pattern, is it? And the new increase method is nothing more than this:

I’m updating the internal state and notifying all observers. That’s all we needed.

Now that the “veil” of the observer pattern is revealed and the mystic behavior of the “hooks” is nothing more than a pre-set set of observers. What do you think about it?

Have you used this pattern before? Have you tried it with the eventEmitter from Node.js? That makes it even easier to implement, since that module is doing all the heavy lifting for us!

Share in the comments what’s your favorite design pattern or the one you’d like to understand better, and I’ll try to cover it next time!

Build applications differently

OSS Tools like Bit offer a new paradigm for building modern apps.

Instead of developing monolithic projects, you first build independent components. Then, you compose your components together to build as many applications as you like. This isn’t just a faster way to build, it’s also much more scalable and helps to standardize development.

It’s fun, give it a try →

An independently source-controlled and shared “card” component. On the right => its dependency graph, auto-generated by Bit.

--

--

I write about technology, freelancing and more. Check out my FREE newsletter if you’re into Software Development: https://fernandodoglio.substack.com/