DEV Community

Cover image for RxJS Simplified - Subjects (marble party!)
 🐀πŸ₯‡ Jasper de Jager
🐀πŸ₯‡ Jasper de Jager

Posted on • Edited on

RxJS Simplified - Subjects (marble party!)

First: WOW

Thanks for all the interest in the RXJS Simplified article! I'd like to repay this enthusiasm with some enthusiasm of my own so I started writing an open source Angular app to create marble machines using RXJS so stay tuned!πŸ˜‰

For now let's continue learning RXJS and see what kind of Subjects (marble machines) RXJS has to offer. We'll use the analogy of a marble party for this one.

Subject

This is the standard Subject. It's Job is to accept data to emit and to emit it to all its observers. At the marble party: You are able to insert new marbles into the machine and these marbles will be emitted to all people at the party (observers). Two things I didn't mention in the first post:
First: The machine can also be turned off. This is done by calling the complete function on the Subject. You now have a closed Subject.
Second: As with any party people can leave early, this means they stop observing the marble machine (unsubscribe).

import { Subject } from "rxjs";

// create the partyMachine
const partyMachine = new Subject();

// Jonah arrived at the party!
const subscriptionJonah = partyMachine.subscribe(
  (marble) => console.log("Jonah", marble)
)

// insert a red marble in the machine
partyMachine.next('red')

// Output:
// Jonah, red

// Charlotte also arrives! better late than never 
const subscriptionCharlotte = partyMachine.subscribe(
  (marble) => console.log("Charlotte", marble)
)

// insert a green marble in the machine
partyMachine.next('green')

// Output:
// Jonah, green
// Charlotte, green

// Jonah has had enough, he leaves
subscriptionJonah.unsubscribe();

// insert a pink marble in the machine
partyMachine.next('pink')

// Output:
// Charlotte, pink

//Party's over! stop the machine
partyMachine.complete();
// Charlotte was automatically sent home! (unsubscribed)

// Here come's Anna, too late as always...
const subscriptionAnna = partyMachine.subscribe(
  (marble) => console.log("Anna", marble)
)
// The machine is off (Subject closed) so Anna gets sent 
// home (unsubscribed) immediately 
Enter fullscreen mode Exit fullscreen mode

ReplaySubject

As you can see in the previous example if you're late to the party you won’t get any marbles (data) until new ones are added to the machine (Subject). There is a solution for this, the ReplaySubject. The ReplaySubject as marble machine: The marble machine keeps track of the last marbles (data) it emitted for those who come late and emits them immediately when they join the party (subscribe). The indented outputs mark the differences with the example of the "normal" Subject.

import { ReplaySubject } from "rxjs";

// create the partyMachine with a memory of 2 marbles
const partyMachine = new ReplaySubject(2);

// Jonah arrived at the party!
const subscriptionJonah = partyMachine.subscribe(
  (marble) => console.log("Jonah", marble)
)

// insert a red marble in the machine
partyMachine.next('red')

// Output:
// Jonah, red

// Charlotte also arrives! better late than never 
const subscriptionCharlotte = partyMachine.subscribe(
  (marble) => console.log("Charlotte", marble)
)

    // Ouput:
    // Charlotte, red

// insert a green marble in the machine
partyMachine.next('green')

// Output:
// Jonah, green
// Charlotte, green

// Jonah has had enough, he leaves
subscriptionJonah.unsubscribe();

// insert a pink marble in the machine
partyMachine.next('pink')

// Output:
// Charlotte, pink

//Party's over! stop the machine
partyMachine.complete();
// Charlotte was automatically sent home! (unsubscribed)

// Here come's Anna, too late as always...
const subscriptionAnna = partyMachine.subscribe(
  (marble) => console.log("Anna", marble)
)
// The machine is off (Subject closed) but still remembers
// the last two marbles

    // Output: 
    // Anna, green       
    // Anna, pink

// Anna gets sent 
// home (unsubscribed) 
Enter fullscreen mode Exit fullscreen mode

A ReplaySubject can remember all marbles

new ReplaySubject();

or just the last N marbles

new ReplaySubject(N)

BehaviorSubject

Sometimes it is easy to get information from outside of the party, this is where the BehaviorSubject comes in. The BehaviorSubject always has a value so it must be initialized with the first value to emit. It also has a getValue method so you can get the last emitted value without having to subscribe. Back to the party: The machine has a way of returning the last emitted marble without having to observe it. Let's say you are now able to call the machine to get the last emitted marble. It will also emit the last marble if you join the party (subscribe).

import { BehaviorSubject} from "rxjs";

// create the partyMachine with an initial value
const partyMachine = new BehaviorSubject('blue');

// Jonah arrived at the party!
const subscriptionJonah = partyMachine.subscribe(
  (marble) => console.log("Jonah", marble)
)

    // Output:
    // Jonah, blue

// insert a red marble in the machine
partyMachine.next('red')

// Output:
// Jonah, red

    // Mom calls to ask the last emitted marble
    console.log("Mom: last marble?", partyMachine.getValue())

    // Output
    // Mom: last marble?, red

// Charlotte also arrives! better late than never 
const subscriptionCharlotte = partyMachine.subscribe(
  (marble) => console.log("Charlotte", marble)
)

    // Ouput:
    // Charlotte, red

// insert a green marble in the machine
partyMachine.next('green')

// Output:
// Jonah, green
// Charlotte, green

// Jonah has had enough, he leaves
subscriptionJonah.unsubscribe();

// insert a pink marble in the machine
partyMachine.next('pink')

// Output:
// Charlotte, pink

//Party's over! stop the machine
partyMachine.complete();
// Charlotte was automatically sent home! (unsubscribed)

// Here come's Anna, too late as always...
const subscriptionAnna = partyMachine.subscribe(
  (marble) => console.log("Anna", marble)
)

// The machine is off (Subject closed) so Anna gets sent 
// home (unsubscribed) immediately

    // Mom calls to ask the last emitted marble
    console.log("Mom: last marble?", partyMachine.getValue())

    // Output
    // Mom: last marble?, pink


Enter fullscreen mode Exit fullscreen mode

What may be unexpected is that the BehaviorSubject doesn't emit the last marble when you subscribe when it is closed (I didn't know this until I made this example and I use RXJS a lot!). Also not that when you use getValue you just get the value, you are not subscribed. Because of this my advice is to only use the BehaviorSubject when you have no other choice because the use of getValue is not reactive programming (you are not at the party and cannot observe the marble machine).

AsyncSubject

The AsyncSubject only emits when it is completed and only emits the last data you gave it. As a marble machine: You can feed all the marbles you want but when you shut it down the observers only get the last marble you put in. I have no idea how this can add to any party so if you know a good example please let me know!

import { AsyncSubject } from "rxjs";

// create the partyMachine
const partyMachine = new AsyncSubject();

// Jonah arrived at the party!
const subscriptionJonah = partyMachine.subscribe(
  (marble) => console.log("Jonah", marble)
)

// insert a red marble in the machine
partyMachine.next('red')

// Charlotte also arrives! better late than never 
const subscriptionCharlotte = partyMachine.subscribe(
  (marble) => console.log("Charlotte", marble)
)

// Jonah has had enough, he leaves
subscriptionJonah.unsubscribe();

// insert a pink marble in the machine
partyMachine.next('pink')

//Party's over! stop the machine
partyMachine.complete();

    // Output:
    // Charlotte, pink

// Charlotte was automatically sent home! (unsubscribed)

// Here come's Anna, too late as always...
const subscriptionAnna = partyMachine.subscribe(
  (marble) => console.log("Anna", marble)
)

// Output:
// Anna, pink

// The machine is off (Subject closed) so Anna gets sent 
// home (unsubscribed) immediately 
Enter fullscreen mode Exit fullscreen mode

Personally I have never used this type of Subject before, never had a case for it, but that doesn't mean you should just forget about it! ( I can think of some cases actually but I'll get back on this Subject when we dive even deeper and play with Pipes/Operators in the next post of this series).

That's all

That are all Subjects RXJS offers. In the next post I'm going to explain Pipes and Operators with an analogy of marble party games!

Top comments (2)

Collapse
 
annervisser profile image
Anner Visser

AsyncSubject is a marble party where you drink too much, you only remember the ending
πŸ˜‚

Collapse
 
jmdejager profile image
🐀πŸ₯‡ Jasper de Jager • Edited

Good thing that's not the one where your mother get's to call to the party πŸ˜‚