Javascript Patterns: Observer Pattern

Javascript Patterns: Observer Pattern

A guide to understanding the Observepattern in Javascript with its pros and cons and real-world use cases.

ยท

3 min read

Hi there folks !๐Ÿ‘‹๐Ÿป today we learn yet another interesting javascript pattern called the Observer pattern. ๐Ÿš€

Let's first talk about the basic observable concept first.

In observable pattern, an observer is an object which can be subscribed by its subscribers (functions), and then those subscribers can then be notified by the observable object

Here is a basic example of a function logger subscribing to the observable object.


function logger(message){
  console.log('This is a' + message);
}

Observable.suscribe(logger)

So, when the notifier is invoked all the data(optional) is passed from the observable to its subscribers or functions that it has invoked.

function logger(message){
  console.log('This is a' + message);
}

Observable.suscribe(logger)      
Observable.notify('Notify subscribers') ;

Implementation

We can export an observer object from observer.js which contains the subscribe and notify methods:

// observer.js
let observers = [];

export default {
 notify: (data) =>  observers.forEach((observer) => observer(data)),
 subscribe: (func) => observers.push(func),
}

We also have a list of functions which are going to subscribe to the observable object we have created above:

// analytics.js

import Observer from './observer.js';
export function sendToGoogleAnalytics(data) {
  console.log('Sent to Google analytics: ', data);
}

export function sendToCustomAnalytics(data) {
  console.log('Sent to custom analytics: ', data);
}

export function sendToEmail(data) {
  console.log('Sent to email: ', data);
}

Now, we can import the observer object from the observer.js file into analytics.js file so that it's functions can subscribe to it.

// analytics.js
export function sendToGoogleAnalytics(data) {
  console.log('Sent to Google analytics: ', data);
}

export function sendToCustomAnalytics(data) {
  console.log('Sent to custom analytics: ', data);
}

export function sendToEmail(data) {
  console.log('Sent to email: ', data);
}

Observer.subscribe(sendToGoogleAnalytics);
Observer.subscribe(sendToCustomAnalytics);
Observer.subscribe(sendToEmail);

Now let's make an index.js file where we can use the notify method to invoke all our subscriber functions with the notify method.

//index.js
import './analytics.js';
import Observer from './observer.js';

Observer.notify('โœจ New data โœจ');

The code above would invoke all the methods in analytics.js which have subscribed to the observable. The power of observable patterns can be seen in the last step in our index.js file where when invoking the .notify method it will pass the message or data to all the functions that have subscribed to the observable object. Let's have a look at the complete code from the above examples in the code editor below with its response in console.

Exercise

The two buttons in our application send 3 different notifications to the user.

Challenge

Create an observer to which these buttons can subscribe. And then on click, both buttons can send all 3 notifications to the user with different data.

Solution:

Tradeoffs

Separation of Concern The observer objects aren't tightly coupled to the observable object and can be (de)coupled at any time. The observable object is responsible for monitoring the events, while the observers simply handle the received data.

Decreased Performance Notifying all subscribers might take a significant amount of time if the observer handling becomes too complex, or if there are too many subscribers to notify.

I hope you enjoyed reading this blog. Please feel free to add your suggestions in the comment section of how we can improve our code and design with this design pattern or even if is it worth the effort to take this approach.

Also please don't forget to follow me on hashnode as i am trying my best to research and bring the best useful content for you. Peace.

ย