Skip to content

Commit

Permalink
docs(multicast): enhance the documentation (#2740)
Browse files Browse the repository at this point in the history
Make clear that multicast can be used in two separate modes.
Describe two modes and provide examples for both. Add note
how multicast relates to Subjects and several publish and
share operators.
  • Loading branch information
mpodlasin authored and benlesh committed Aug 29, 2017
1 parent 5b8a7c1 commit d926435
Showing 1 changed file with 85 additions and 10 deletions.
95 changes: 85 additions & 10 deletions src/operator/multicast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,96 @@ export function multicast<T>(SubjectFactory: (this: Observable<T>) => Subject<T>
/* tslint:enable:max-line-length */

/**
* Returns an Observable that emits the results of invoking a specified selector on items
* emitted by a ConnectableObservable that shares a single subscription to the underlying stream.
* Allows source Observable to be subscribed only once with a Subject of choice,
* while still sharing its values between multiple subscribers.
*
* <span class="informal">Subscribe to Observable once, but send its values to multiple subscribers.</span>
*
* <img src="./img/multicast.png" width="100%">
*
* @param {Function|Subject} subjectOrSubjectFactory - Factory function to create an intermediate subject through
* which the source sequence's elements will be multicast to the selector function
* or Subject to push source elements into.
* @param {Function} [selector] - Optional selector function that can use the multicasted source stream
* `multicast` is an operator that works in two modes.
*
* In the first mode you provide a single argument to it, which can be either an initialized Subject or a Subject
* factory. As a result you will get a special kind of an Observable - a {@link ConnectableObservable}. It can be
* subscribed multiple times, just as regular Observable, but it won't subscribe to the source Observable at that
* moment. It will do it only if you call its `connect` method. This means you can essentially control by hand, when
* source Observable will be actually subscribed. What is more, ConnectableObservable will share this one subscription
* between all of its subscribers. This means that, for example, `ajax` Observable will only send a request once,
* even though usually it would send a request per every subscriber. Since it sends a request at the moment of
* subscription, here request would be sent when the `connect` method of a ConnectableObservable is called.
*
* The most common pattern of using ConnectableObservable is calling `connect` when the first consumer subscribes,
* keeping the subscription alive while several consumers come and go and finally unsubscribing from the source
* Observable, when the last consumer unsubscribes. To not implement that logic over and over again,
* ConnectableObservable has a special operator, `refCount`. When called, it returns an Observable, which will count
* the number of consumers subscribed to it and keep ConnectableObservable connected as long as there is at least
* one consumer. So if you don't actually need to decide yourself when to connect and disconnect a
* ConnectableObservable, use `refCount`.
*
* The second mode is invoked by calling `multicast` with an additional, second argument - selector function.
* This function accepts an Observable - which basically mirrors the source Observable - and returns Observable
* as well, which should be the input stream modified by any operators you want. Note that in this
* mode you cannot provide initialized Subject as a first argument - it has to be a Subject factory. If
* you provide selector function, `multicast` returns just a regular Observable, instead of ConnectableObservable.
* Thus, as usual, each subscription to this stream triggers subscription to the source Observable. However,
* if inside the selector function you subscribe to the input Observable multiple times, actual source stream
* will be subscribed only once. So if you have a chain of operators that use some Observable many times,
* but you want to subscribe to that Observable only once, this is the mode you would use.
*
* Subject provided as a first parameter of `multicast` is used as a proxy for the single subscription to the
* source Observable. It means that all values from the source stream go through that Subject. Thus, if a Subject
* has some special properties, Observable returned by `multicast` will have them as well. If you want to use
* `multicast` with a Subject that is one of the ones included in RxJS by default - {@link Subject},
* {@link AsyncSubject}, {@link BehaviorSubject}, or {@link ReplaySubject} - simply use {@link publish},
* {@link publishLast}, {@link publishBehavior} or {@link publishReplay} respectively. These are actually
* just wrappers around `multicast`, with a specific Subject hardcoded inside.
*
* Also, if you use {@link publish} or {@link publishReplay} with a ConnectableObservables `refCount` operator,
* you can simply use {@link share} and {@link shareReplay} respectively, which chain these two.
*
* @example <caption>Use ConnectableObservable</caption>
* const seconds = Rx.Observable.interval(1000);
* const connectableSeconds = seconds.multicast(new Subject());
*
* connectableSeconds.subscribe(value => console.log('first: ' + value));
* connectableSeconds.subscribe(value => console.log('second: ' + value));
*
* // At this point still nothing happens, even though we subscribed twice.
*
* connectableSeconds.connect();
*
* // From now on `seconds` are being logged to the console,
* // twice per every second. `seconds` Observable was however only subscribed once,
* // so under the hood Observable.interval had only one clock started.
*
* @example <caption>Use selector</caption>
* const seconds = Rx.Observable.interval(1000);
*
* seconds
* .multicast(
* () => new Subject(),
* seconds => seconds.zip(seconds) // Usually zip would subscribe to `seconds` twice.
* // Because we are inside selector, `seconds` is subscribed once,
* ) // thus starting only one clock used internally by Observable.interval.
* .subscribe();
*
* @see {@link publish}
* @see {@link publishLast}
* @see {@link publishBehavior}
* @see {@link publishReplay}
* @see {@link share}
* @see {@link shareReplay}
*
* @param {Function|Subject} subjectOrSubjectFactory - Factory function to create an intermediate Subject through
* which the source sequence's elements will be multicast to the selector function input Observable or
* ConnectableObservable returned by the operator.
* @param {Function} [selector] - Optional selector function that can use the input stream
* as many times as needed, without causing multiple subscriptions to the source stream.
* Subscribers to the given source will receive all notifications of the source from the
* Subscribers to the input source will receive all notifications of the source from the
* time of the subscription forward.
* @return {Observable} An Observable that emits the results of invoking the selector
* on the items emitted by a `ConnectableObservable` that shares a single subscription to
* the underlying stream.
* @return {Observable<T>|ConnectableObservable<T>} An Observable that emits the results of invoking the selector
* on the source stream or a special {@link ConnectableObservable}, if selector was not provided.
*
* @method multicast
* @owner Observable
*/
Expand Down

0 comments on commit d926435

Please sign in to comment.