Observer Design Pattern in JavaScript

There are many times when one part of the application changes, other parts needs to be updated. In AngularJS, if the $scope object updates, an event can be triggered to notify another component. The observer pattern incorporates just that – if an object is modified it broadcasts to dependent objects that a change has occurred.

Another prime example is the model-view-controller (MVC) architecture; The view updates when the model changes. One benefit is decoupling the view from the model to reduce dependencies.

Observer Design Pattern Observer Design Pattern on Wikipedia

As shown in the UML diagram, the necessary objects are the subject, observer, and concrete objects. The subject contains references to the concrete observers to notify for any changes. The Observer object is an abstract class that allows for the concrete observers to implements the notify method.

Let’s take a look at an AngularJS example that encompasses the observer pattern through event management.

// Controller 1 $scope.$on('nameChanged', function(event, args) {     $scope.name = args.name; });  ...  // Controller 2 $scope.userNameChanged = function(name) {     $scope.$emit('nameChanged', {name: name}); }; 

With the observer pattern, it is important to distinguish the independent object or the subject.

It is important to note that although the observer pattern does offer many advantages, one of the disadvantages is a significant drop in performance as the number of observers increased. One of the most notorious observers is watchers. In AngularJS, we can watch variables, functions, and objects. The $$digest cycle runs and notifies each of the watchers with the new values whenever a scope object is modified.

We can create our own Subjects and Observers in JavaScript. Let’s see how this is implemented:

var Subject = function() {     this.observers = [];      return {     subscribeObserver: function(observer) {         this.observers.push(observer);     },     unsubscribeObserver: function(observer) {         var index = this.observers.indexOf(observer);         if(index > -1) {         this.observers.splice(index, 1);         }     },     notifyObserver: function(observer) {         var index = this.observers.indexOf(observer);         if(index > -1) {         this.observers[index].notify(index);         }     },     notifyAllObservers: function() {         for(var i = 0; i < this.observers.length; i++){         this.observers[i].notify(i);         };     }     }; };  var Observer = function() {     return {     notify: function(index) {         console.log("Observer " + index + " is notified!");     }     } }  var subject = new Subject();  var observer1 = new Observer(); var observer2 = new Observer(); var observer3 = new Observer(); var observer4 = new Observer();  subject.subscribeObserver(observer1); subject.subscribeObserver(observer2); subject.subscribeObserver(observer3); subject.subscribeObserver(observer4);  subject.notifyObserver(observer2); // Observer 2 is notified!  subject.notifyAllObservers(); // Observer 1 is notified! // Observer 2 is notified! // Observer 3 is notified! // Observer 4 is notified! 

Publish/Subscribe

The Publish/Subscribe pattern, however, uses a topic/event channel that sits between the objects wishing to receive notifications (subscribers) and the object firing the event (the publisher). This event system allows code to define application-specific events that can pass custom arguments containing values needed by the subscriber. The idea here is to avoid dependencies between the subscriber and publisher.

This differs from the Observer pattern since any subscriber implementing an appropriate event handler to register for and receive topic notifications broadcast by the publisher.

Many developers choose to aggregate the publish/subscribe design pattern with the observer though there is a distinction. Subscribers in the publish/subscribe pattern are notified through some messaging medium, but observers are notified by implementing a handler similar to the subject.

In AngularJS, a subscriber ‘subscribes’ to an event using $on('event’, callback), and a publisher 'publishes’ an event using $emit('event’, args) or $broadcast('event’, args).