How to Use Observables with Vanilla JavaScript
Tags: javascript, programming, webdev
Published: 2021-12-31 09:36:37

### No frameworks used, just pure vanilla JavaScript.
<br>
While working on a side project just for fun, I wanted to write a JavaScript script to call a REST API and eventually do some cool stuff on a webpage. It is purely vanilla JavaScript, with no fancy frameworks or even libraries being used.

First, I thought of using **Promises** for my calls and this was easy for me. I have done that a ton of times. However, it then hit me hard — why don’t I use **Observables?** I knew that vanilla JavaScript didn’t natively support Observables. But couldn’t I implement it myself? And that’s what I did.


![How to Use Observables with Vanilla JavaScript (JS) without any frameworks or libraries. Code Coding Programming Software Web Development](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gxbdlaqkyungajo78k87.png)

## This is how I thought things through

 1. The Observable itself would be of a new object type called **Subject.**

 2. This **Subject** object should expose the subscribe and next functions.

 3. subscribe should be called by observers to subscribe to the observable stream of data.

 4. next should be called by the **Subject** owner to push/publish new data whenever available.

 5. Additionally, I wanted the **Subject** owner to be able to know whenever no observers were interested in its data. This would enable the **Subject** owner to decide if he still wanted to get the data or not.

 6. Also, the **Subject** owner should be able to know whenever at least one observer started being interested in its data. This would give the **Subject** owner more control on its data flow and any related operations.

 7. Now back to the **observer**. He should be able to **unsubscribe** from the **Subject** at any time.

 8. This leads us to a new object type called **Subscription.**

 9. This **Subscription** object should expose an unsubscribe function.

 10. unsubscribe should be called by the **observer** whenever he wants to stop listening to the data stream coming from the **Subject**.

Following these rules, I came up with the following implementation.

![How to Use Observables with Vanilla JavaScript (JS) without any frameworks or libraries. Code Coding Programming Software Web Development](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gxbdlaqkyungajo78k87.png)

## Implementation

### Subscription

```javascript
let Subscription = function(handlerId, unsubscribeNotificationCallback) {
	let self = this;

	self.unsubscribe = () => {
		if(unsubscribeNotificationCallback) {
			unsubscribeNotificationCallback(handlerId);
		}
	};
	
	return self;
};
```

Note that **Subscription** just notifies the **Subject** when the unsubscribe function is called.

---

### Subject

```javascript
let Subject = function(subscribersStateChangeNotificationCallback) {
	let self = this;
	
	let handlers = {};
	
	Object.defineProperty(self, "subscribersFound", {
		get() {
			let found = false;
			
			for(const prop in handlers) {
				if(handlers.hasOwnProperty(prop)) {
					found = true;
					break;
				}
			}
			
			return found;
		}
	});
	
	Object.defineProperty(self, "subscribersCount", {
		get() {
			let count = 0;
			
			for(const prop in handlers) {
				if(handlers.hasOwnProperty(prop)) {
					count++;
				}
			}
			
			return count;
		}
	});
	
	let unsubscribeNotificationCallback = (handlerId) => {
		if(handlerId && handlerId !== '' && handlers.hasOwnProperty(handlerId)) {
			delete handlers[handlerId];
			
			if(subscribersStateChangeNotificationCallback && !self.subscribersFound) {
				subscribersStateChangeNotificationCallback(false);
			}
		}
	};
	
	self.subscribe = (handler) => {
		let handlerId = createGuid();
		handlers[handlerId] = handler;
		
		if(subscribersStateChangeNotificationCallback && self.subscribersCount === 1) {
			subscribersStateChangeNotificationCallback(true);
		}
		
		return new Subscription(handlerId, unsubscribeNotificationCallback);
	};
	
	self.next = (data) => {
		for(const handlerId in handlers) {
			handlers[handlerId](data);
		}
	};
	
	return self;
};

let createGuid = function() {  
   return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {  
      var r = Math.random()*16|0, v = c === 'x' ? r : (r&0x3|0x8);  
      return v.toString(16);  
   });  
};
```

---

### Somewhere in the Subject Owner

```javascript
.
.
.
let subscribersStateChangeNotificationCallback = (subscriberFound) => {
	if(!subscriberFound && isNowWatching) {
		stopWatching();
		isNowWatching = false;
	} else if(subscriberFound && !isNowWatching) {
		startWatching();
	}
};

self.data = new Subject(subscribersStateChangeNotificationCallback);
.
.
.
self.data.next(self.snapshot.data);
.
.
.
```

---

### Somewhere in the Observer

```javascript
.
.
.
const dashboardServiceSubscription = myDashboardService.data.subscribe((data) => {
	...
});
.
.
.
dashboardServiceSubscription.unsubscribe();
.
.
.
```

![How to Use Observables with Vanilla JavaScript (JS) without any frameworks or libraries. Code Coding Programming Software Web Development](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gxbdlaqkyungajo78k87.png)

That’s it, everything worked like a charm and I was proud of what I achieved.

So, the punch line is that coding in vanilla JavaScript is not always equal to writing boring code, you can make it much more fun 😃
<br>
Hope you found reading this story as interesting as I found writing it.
<br><br>
This article was originally published [here](https://www.developmentsimplyput.com/post/how-to-use-observables-with-vanilla-javascript).