The documentation for RxJS
defines AsyncSubject
as follows:
The AsyncSubject is a variant where only the last value of the Observable execution is sent to its observers, and only when the execution completes.
I don't see where / why I would ever need to use this variant of subject. Can someone provide an explanation or a real-world example to illustrate why it exists and its advantages?
AsyncSubject is a variant of a Subject which keeps the last value emitted by a source observable before completion and sends it to all new subscriptions.
In comparison to a regular Observable, a Subject allows values to be multicasted to many Observers. A Subject and its subscribers have a one-to-many relationship. A Subject can be an Observable as well as an Observer. They hold a registry of many listeners to multiple Observables.
The ReplaySubject is comparable to the BehaviorSubject in the way that it can send “old” values to new subscribers. It however has the extra characteristic that it can record a part of the observable execution and therefore store multiple old values and “replay” them to new subscribers.
Subject adds them to its collection observers. Whenever there is a value in the stream it notifies all of its Observers. The Subject also implements the next , error & complete methods. Hence it can subscribe to another observable and receive values from it.
It looks like it could be useful for fetching and caching (one-shot) resources, since generally http.get will emit one response then complete.
From rxjs/spec/subjects/AsyncSubject-spec.ts
it('should emit the last value when complete', () => {
it('should emit the last value when subscribing after complete', () => {
it('should keep emitting the last value to subsequent subscriptions', () => {
Components that subscribe after the fetch will then pick up value, which is not the case for Subject
const subject = new Rx.Subject();
const asyncSubject = new Rx.AsyncSubject();
// Subscribe before
subject.subscribe(x => console.log('before complete - subject', x))
asyncSubject.subscribe(x => console.log('before complete - asyncSubject', x))
subject.next('value 1');
subject.complete();
subject.next('value 2');
asyncSubject.next('value 1');
asyncSubject.complete();
asyncSubject.next('value 2');
// Subscribe after
subject.subscribe(x => console.log('after complete - subject', x))
asyncSubject.subscribe(x => console.log('after complete - asyncSubject', x))
.as-console-wrapper { max-height: 100% ! important; top: 0 }
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.6/Rx.js"></script>
Cool!
And just for fun, I added handlers to log complete events to show they are raised in either case (Subject or AsyncSubject) when a subscribe happens after a subject is completed.
Also added BehaviorSubject.
const subject = new Rx.Subject();
const asyncSubject = new Rx.AsyncSubject();
const behaviorSubject = new Rx.BehaviorSubject();
console.log('before init - behaviorSubject', behaviorSubject.value)
subject.next('INIT');
asyncSubject.next('INIT');
behaviorSubject.next('INIT');
console.log('before subscribe - behaviorSubject', behaviorSubject.value)
// Subscribe before
subject.subscribe(x => console.log('before complete - subject', x))
asyncSubject.subscribe(x => console.log('before complete - asyncSubject', x))
behaviorSubject.subscribe(x => console.log('before complete - behaviorSubject', x))
subject.next('NEXT');
subject.complete();
asyncSubject.next('NEXT');
asyncSubject.complete();
behaviorSubject.next('NEXT');
behaviorSubject.complete();
// Subscribe after
subject.subscribe({
next: x => console.log('after complete - subject', x),
complete: () => console.log('after complete - subject COMPLETE')
})
asyncSubject.subscribe({
next: x => console.log('after complete - asyncSubject', x),
complete: () => console.log('after complete - asyncSubject COMPLETE')
})
behaviorSubject.subscribe({
next: x => console.log('after complete - behaviorSubject', x),
complete: () => console.log('after complete - behaviorSubject COMPLETE')
})
.as-console-wrapper { max-height: 100% ! important; top: 0 }
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.6/Rx.js"></script>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With