One important thing to understand when you are working with Reactive Programming is the difference between hot and cold observables.
Let’s start with the definition of both types:
Cold Observables
Cold observables start running upon subscription: the observable sequence only starts pushing values to the observers when subscribe is called.
Values are also not shared among subscribers.
Hot Observables
When an observer subscribes to a hot observable sequence, it will get all values in the stream that are emitted after it subscribes.
The hot observable sequence is shared among all subscribers, and each subscriber is pushed the next value in the sequence.
Let’s see now how these 2 different observables are used across a sample application.
Using the same application I started to describe in my previous blog post, we can spot in the main class some code that is commented.
The first part represent how a cold observable works, so if you try to have the following code inside App.js you can immediately understand what’s going on when an observer subscribes to a cold observable:
let engine = new BallsCallSystem(); let t1 = new Ticket("t1", engine.ballStream); setTimeout(()=>{ let t2 = new Ticket("t2", engine.ballStream); }, 5000); engine.startGame();
Our game engine instead has the following code in order to share the balls called across the tickets:
let stream = Rx.Observable .interval(INTERVAL) .map((value) => {return numbersToCall[value]}) .take(TOTAL_CALLS); this.published = stream.publish();
As you can see when we start the game there is only 1 ticket bought by the user, then after 5 seconds the user bought a new ticket and in theory we should check if in that ticket all the numbers previously called are present or not.
But with cold observables when an observer subscribe, it won’t be able to receive the previous data but just the data since when it subscribed, completely broken the main purpose of our bingo game… we definitely need something different in order to work with it, potentially something that won’t completely change our game logic but that could be useful to fix the issue…
That’s where the hot observables come in!
The cool part of hot observables is that you can define how much data you want to buffer inside the memory, sometimes you need to store all of them (like in the bingo game) sometimes you need only the last 4-5 occurrences, but as you will see changing from a cold to an hot observables it’s a matter of 1 line of code!
Inside the same git repo, you can find a class called BallsCallSystemReplay, this class implement an hot observable, let’s see how much the code changed inside our game engine:
this.stream = Rx.Observable .interval(INTERVAL) .map((value) => {return numbersToCall[value]}) .take(TOTAL_CALLS) .shareReplay();
Basically we removed the publish method after creating the stream (that was useful if you want to control when the observable starts to stream data) and we added shareReplay that is a method that transform a cold observable to an hot one sharing all the data pass trough the stream every time a new observer subscribe to it.
So now if we change the code in App.js in this way:
let engine = new BallsCallSystemReplay(); let t1 = new Ticket("t1", engine.ballStream); setTimeout(function() { let t2 = new Ticket("t2", engine.ballStream); }, 5000);
Now you can see that when the second ticket is bought after the game started, we’re going anyway to check all the values called by the engine without doing a massive refactor of our game logic! Below you can see when the second ticket subscribe to the hot observable, the first thing is going to receive are all the previous values called by the engine and then is receiving the data with a certain interval following the logic of the game.
