Skip to content

Instantly share code, notes, and snippets.

@royling
Last active June 7, 2024 08:01
Show Gist options
  • Save royling/b9f2c858dfd836911665ce5361f20bcf to your computer and use it in GitHub Desktop.
Save royling/b9f2c858dfd836911665ce5361f20bcf to your computer and use it in GitHub Desktop.
RxJS5: sync vs. async observables

Sync observables created from a synchronous source will emit values synchronously, so the observers will receive values in the order of subscription.

The source iterable is traversed for each observer subscribed. For example, the size of source iterable is M, there are N observers, so the traversal times is M*N. This is explained in RxJS5 Manual:

Plain Observables are unicast (each subscribed Observer owns an independent execution of the Observable)

let sub = Rx.Observable.range(0, 3);

sub.subscribe(value => console.log(`observer 1: ${value}`));
sub.subscribe(value => console.log(`observer 2: ${value}`));

// =>
// observer 1: 0
// observer 1: 1
// observer 1: 2
// observer 2: 0
// observer 2: 1
// observer 2: 1

Async observable emits values over time, so each time a value is emitted, all observers subscribed will react to the emitted value.

let sub = Rx.Observable.interval(200).take(3); // emit 0, 1, 2 every 200ms

sub.subscribe(value => console.log(`observer 1: ${value}`));
sub.subscribe(value => console.log(`observer 2: ${value}`));

// =>
// observer 1: 0
// observer 2: 0
// observer 1: 1
// observer 2: 1
// observer 1: 2
// observer 2: 2

An RxJS Subject is a special type of Observable that allows values to be multicasted to many Observers.

let source = Rx.Observable.range(0, 2); // sync
let sub = new Rx.Subject();

sub.subscribe(value => console.log(`observer 1: ${value}`));
sub.subscribe(value => console.log(`observer 2: ${value}`));

source.subscribe(sub); // multicast/notify each value to all subscribed observers (ie. listeners)

sub.subscribe(value => console.log(`observer 3: ${value}`)); // no values emitted to this observer!

// =>
// observer 1: 0
// observer 2: 0
// observer 1: 1
// observer 2: 1

Compare this against the first example in sync-vs-async.md, worth of noting how subject behaves differently against observable, and the third subscriber which is subscribed after values are emitted will not be notified. Also in this case, subject and observer/listener are the equivalent terms commonly used in Observer design pattern.

Let's change the source observable to async:

let source = Rx.Observable.interval(200).take(2);
...

// =>
// observer 1: 0
// observer 2: 0
// observer 3: 0
// observer 1: 1
// observer 2: 1
// observer 3: 1

The values are emitted to all 3 observers over time. In this case specifically, there's no diffs between subject and observable.

You may already note the differences between unicast observable and multicast observable in the other files. Here's the key takeways from RxJS5 docs:

  • Plain Observables are unicast (each subscribed Observer owns an independent execution of the Observable), aka. cold.
  • A multicasted Observable uses a Subject under the hood to make multiple Observers see the same Observable execution.
  • How multicast operator works under the hood: Observers subscribe to an underlying Subject, and the Subject subscribes to the source Observable.
  • Subjects are the only way of making any Observable execution be shared to multiple Observers.
  • A few specializations of the Subject type: BehaviorSubject, ReplaySubject, and AsyncSubject.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment