diff --git a/src/operator/multicast.ts b/src/operator/multicast.ts index 5438f4bf9f..90074df9fb 100644 --- a/src/operator/multicast.ts +++ b/src/operator/multicast.ts @@ -10,21 +10,96 @@ export function multicast(SubjectFactory: (this: Observable) => Subject /* 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. + * + * Subscribe to Observable once, but send its values to multiple subscribers. * * * - * @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 Use ConnectableObservable + * 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 Use selector + * 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|ConnectableObservable} 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 */