UNPKG

@reactivex/rxjs

Version:

Reactive Extensions for modern JavaScript

149 lines 5.89 kB
"use strict"; var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); } return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); Object.defineProperty(exports, "__esModule", { value: true }); var Subscriber_1 = require("../Subscriber"); /** * Make a {@link ConnectableObservable} behave like a ordinary observable and automates the way * you can connect to it. * * Internally it counts the subscriptions to the observable and subscribes (only once) to the source if * the number of subscriptions is larger than 0. If the number of subscriptions is smaller than 1, it * unsubscribes from the source. This way you can make sure that everything before the *published* * refCount has only a single subscription independently of the number of subscribers to the target * observable. * * Note that using the {@link share} operator is exactly the same as using the *publish* operator * (making the observable hot) and the *refCount* operator in a sequence. * * ![](refCount.png) * * ## Example * * In the following example there are two intervals turned into connectable observables * by using the *publish* operator. The first one uses the *refCount* operator, the * second one does not use it. You will notice that a connectable observable does nothing * until you call its connect function. * * ```ts * import { interval } from 'rxjs'; * import { tap, publish, refCount } from 'rxjs/operators'; * * // Turn the interval observable into a ConnectableObservable (hot) * const refCountInterval = interval(400).pipe( * tap((num) => console.log(`refCount ${num}`)), * publish(), * refCount() * ); * * const publishedInterval = interval(400).pipe( * tap((num) => console.log(`publish ${num}`)), * publish() * ); * * refCountInterval.subscribe(); * refCountInterval.subscribe(); * // 'refCount 0' -----> 'refCount 1' -----> etc * // All subscriptions will receive the same value and the tap (and * // every other operator) before the publish operator will be executed * // only once per event independently of the number of subscriptions. * * publishedInterval.subscribe(); * // Nothing happens until you call .connect() on the observable. * ``` * * @see {@link ConnectableObservable} * @see {@link share} * @see {@link publish} */ function refCount() { return function refCountOperatorFunction(source) { return source.lift(new RefCountOperator(source)); }; } exports.refCount = refCount; var RefCountOperator = /** @class */ (function () { function RefCountOperator(connectable) { this.connectable = connectable; } RefCountOperator.prototype.call = function (subscriber, source) { var connectable = this.connectable; connectable._refCount++; var refCounter = new RefCountSubscriber(subscriber, connectable); var subscription = source.subscribe(refCounter); if (!refCounter.closed) { refCounter.connection = connectable.connect(); } return subscription; }; return RefCountOperator; }()); var RefCountSubscriber = /** @class */ (function (_super) { __extends(RefCountSubscriber, _super); function RefCountSubscriber(destination, connectable) { var _this = _super.call(this, destination) || this; _this.connectable = connectable; return _this; } RefCountSubscriber.prototype._unsubscribe = function () { var connectable = this.connectable; if (!connectable) { this.connection = null; return; } this.connectable = null; var refCount = connectable._refCount; if (refCount <= 0) { this.connection = null; return; } connectable._refCount = refCount - 1; if (refCount > 1) { this.connection = null; return; } /// // Compare the local RefCountSubscriber's connection Subscription to the // connection Subscription on the shared ConnectableObservable. In cases // where the ConnectableObservable source synchronously emits values, and // the RefCountSubscriber's downstream Observers synchronously unsubscribe, // execution continues to here before the RefCountOperator has a chance to // supply the RefCountSubscriber with the shared connection Subscription. // For example: // ``` // range(0, 10).pipe( // publish(), // refCount(), // take(5), // ) // .subscribe(); // ``` // In order to account for this case, RefCountSubscriber should only dispose // the ConnectableObservable's shared connection Subscription if the // connection Subscription exists, *and* either: // a. RefCountSubscriber doesn't have a reference to the shared connection // Subscription yet, or, // b. RefCountSubscriber's connection Subscription reference is identical // to the shared connection Subscription /// var connection = this.connection; var sharedConnection = connectable._connection; this.connection = null; if (sharedConnection && (!connection || sharedConnection === connection)) { sharedConnection.unsubscribe(); } }; return RefCountSubscriber; }(Subscriber_1.Subscriber)); //# sourceMappingURL=refCount.js.map