What are the semantics of different RxJS subjects?

Ivan Kleshnin picture Ivan Kleshnin · Jan 18, 2016 · Viewed 14.1k times · Source

Documentation for the topic is sparse and it's hard to discover an "entry-point" there.

Answer

user3743222 picture user3743222 · Jan 18, 2016

Semantics differ according to the type of subjects. I will divide them in two kinds : vanilla (Rx.Subject), and special-purpose subjects (the other three). The special-purpose subjects share part of the semantics of the vanilla subject with a few caveats due to their specialization (for instance, completion/reconnection behaviour).

Vanilla Rx.Subject semantics

  1. Key features

    • subjects implement the observer, observable interface (and the disposable interface as they have a dispose handler on their prototype). That means, among other things, they have:
      • observer interface : onNext, onError, onComplete method
      • observable interface : subscribe method
    • you can cast a subject to an observer or to an observable, hiding the implementation of the extra interfaces (cf. .asObserver(), and .asObservable()) if need be
    • the subject being an observable, you can subscribe several observers to it. That observable will then broadcast its data to all its observers. Internally the subject maintains an array of observers.
    • the subject being an observer, you can subscribe it to any observable
    • the observer and the observable which compose the subject being two distinct entities, you can use them independently of the other if that's your use case.
    • disposeing a subject will unsubscribe all observers and release resources.
    • Subjects do not take a scheduler but rather assume that all serialization and grammatical correctness are handled by the caller of the subject.
    • The default behaviour of subjects is to emit synchronously their values to the observers, starting with the first subscribed observer to the last. In most cases, order will not matter, in others it will.

I quote a key aspect of Rxjs contract and grammar :

This grammar allows observable sequences to send any amount (0 or more) of onNext messages to the subscribed observer instance, optionally followed by a single success (onCompleted) or failure (onError) message.

  • a vanilla subject (created with new Rx.Subject()) implements that grammar : when onCompleted has been called once, all subsequent calls to onNext are ignored. Second call of onCompleted on the same observer is also ignored. If an observer subscribes to the observable side of the subject, its onComplete callback will immediately be called (http://jsfiddle.net/cLf6Lqsn/1/).

    1. Creation

      • new Rx.Subject()

    Returns a subject which connects its observer to its observable (jsfiddle). This example is taken from the official documentation and portrays how to use subjects as proxies. The subject is subscribed to a source (observer side), and is also listened on by observers (observable side). Any call to onNext (observer side) results in the observable side calling onNext with the same value for each of its observers.

    • Rx.Subject.create(observer, observable)

    Creates a subject from the specified observer and observable. Those two are not necessarily connected. A good example can be seen in the implementation of Rx.Dom.fromWebSocket which returns a subject used to send and receive data from a socket. The observer side of the subject sends data to the socket. The observable side is used to listen on incoming data from the socket. Also, a subject created this way does NOT have a dispose method.

Specialized Rx.Subject semantics

  • This reactivex.io documentation covers pretty well most of the semantics of the specialized subjects.
  • The other interesting points to mention concern behavior past completion.
  • Sample code illustrating the behaviour are here for async, behavior, replay

Hopefully I did not get too much wrong. I'll be happy to be corrected. Last note, this should be valid for RxJS v4.

For a detailed explanation of the behaviour of cold/hot observables, one can refer to : Hot and Cold observables : are there 'hot' and 'cold' operators?