/ajax/libs/rxjs/2.3.20/rx.backpressure.js
JavaScript | 424 lines | 328 code | 62 blank | 34 comment | 74 complexity | c9e5a2dae83983d8e5ac6050e70c3e50 MD5 | raw file
- // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
-
- ;(function (factory) {
- var objectTypes = {
- 'boolean': false,
- 'function': true,
- 'object': true,
- 'number': false,
- 'string': false,
- 'undefined': false
- };
-
- var root = (objectTypes[typeof window] && window) || this,
- freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports,
- freeModule = objectTypes[typeof module] && module && !module.nodeType && module,
- moduleExports = freeModule && freeModule.exports === freeExports && freeExports,
- freeGlobal = objectTypes[typeof global] && global;
-
- if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal)) {
- root = freeGlobal;
- }
-
- // Because of build optimizers
- if (typeof define === 'function' && define.amd) {
- define(['rx'], function (Rx, exports) {
- return factory(root, exports, Rx);
- });
- } else if (typeof module === 'object' && module && module.exports === freeExports) {
- module.exports = factory(root, module.exports, require('./rx'));
- } else {
- root.Rx = factory(root, {}, root.Rx);
- }
- }.call(this, function (root, exp, Rx, undefined) {
-
- // References
- var Observable = Rx.Observable,
- observableProto = Observable.prototype,
- AnonymousObservable = Rx.AnonymousObservable,
- CompositeDisposable = Rx.CompositeDisposable,
- Subject = Rx.Subject,
- Observer = Rx.Observer,
- disposableEmpty = Rx.Disposable.empty,
- disposableCreate = Rx.Disposable.create,
- inherits = Rx.internals.inherits,
- addProperties = Rx.internals.addProperties,
- timeoutScheduler = Rx.Scheduler.timeout,
- identity = Rx.helpers.identity;
-
- var objectDisposed = 'Object has been disposed';
- function checkDisposed() { if (this.isDisposed) { throw new Error(objectDisposed); } }
-
- var PausableObservable = (function (_super) {
-
- inherits(PausableObservable, _super);
-
- function subscribe(observer) {
- var conn = this.source.publish(),
- subscription = conn.subscribe(observer),
- connection = disposableEmpty;
-
- var pausable = this.pauser.distinctUntilChanged().subscribe(function (b) {
- if (b) {
- connection = conn.connect();
- } else {
- connection.dispose();
- connection = disposableEmpty;
- }
- });
-
- return new CompositeDisposable(subscription, connection, pausable);
- }
-
- function PausableObservable(source, pauser) {
- this.source = source;
- this.controller = new Subject();
-
- if (pauser && pauser.subscribe) {
- this.pauser = this.controller.merge(pauser);
- } else {
- this.pauser = this.controller;
- }
-
- _super.call(this, subscribe);
- }
-
- PausableObservable.prototype.pause = function () {
- this.controller.onNext(false);
- };
-
- PausableObservable.prototype.resume = function () {
- this.controller.onNext(true);
- };
-
- return PausableObservable;
-
- }(Observable));
-
- /**
- * Pauses the underlying observable sequence based upon the observable sequence which yields true/false.
- * @example
- * var pauser = new Rx.Subject();
- * var source = Rx.Observable.interval(100).pausable(pauser);
- * @param {Observable} pauser The observable sequence used to pause the underlying sequence.
- * @returns {Observable} The observable sequence which is paused based upon the pauser.
- */
- observableProto.pausable = function (pauser) {
- return new PausableObservable(this, pauser);
- };
-
- function combineLatestSource(source, subject, resultSelector) {
- return new AnonymousObservable(function (observer) {
- var hasValue = [false, false],
- hasValueAll = false,
- isDone = false,
- values = new Array(2),
- err;
- function next(x, i) {
- values[i] = x
- var res;
- hasValue[i] = true;
- if (hasValueAll || (hasValueAll = hasValue.every(identity))) {
- if (err) {
- observer.onError(err);
- return;
- }
- try {
- res = resultSelector.apply(null, values);
- } catch (ex) {
- observer.onError(ex);
- return;
- }
- observer.onNext(res);
- }
- if (isDone && values[1]) {
- observer.onCompleted();
- }
- }
- return new CompositeDisposable(
- source.subscribe(
- function (x) {
- next(x, 0);
- },
- function (e) {
- if (values[1]) {
- observer.onError(e);
- } else {
- err = e;
- }
- },
- function () {
- isDone = true;
- values[1] && observer.onCompleted();
- }),
- subject.subscribe(
- function (x) {
- next(x, 1);
- },
- observer.onError.bind(observer),
- function () {
- isDone = true;
- next(true, 1);
- })
- );
- });
- }
- var PausableBufferedObservable = (function (__super__) {
- inherits(PausableBufferedObservable, __super__);
- function subscribe(observer) {
- var q = [], previousShouldFire;
- var subscription =
- combineLatestSource(
- this.source,
- this.pauser.distinctUntilChanged().startWith(false),
- function (data, shouldFire) {
- return { data: data, shouldFire: shouldFire };
- })
- .subscribe(
- function (results) {
- if (previousShouldFire !== undefined && results.shouldFire != previousShouldFire) {
- previousShouldFire = results.shouldFire;
- // change in shouldFire
- if (results.shouldFire) {
- while (q.length > 0) {
- observer.onNext(q.shift());
- }
- }
- } else {
- previousShouldFire = results.shouldFire;
- // new data
- if (results.shouldFire) {
- observer.onNext(results.data);
- } else {
- q.push(results.data);
- }
- }
- },
- function (err) {
- // Empty buffer before sending error
- while (q.length > 0) {
- observer.onNext(q.shift());
- }
- observer.onError(err);
- },
- function () {
- // Empty buffer before sending completion
- while (q.length > 0) {
- observer.onNext(q.shift());
- }
- observer.onCompleted();
- }
- );
- return subscription;
- }
- function PausableBufferedObservable(source, pauser) {
- this.source = source;
- this.controller = new Subject();
- if (pauser && pauser.subscribe) {
- this.pauser = this.controller.merge(pauser);
- } else {
- this.pauser = this.controller;
- }
- __super__.call(this, subscribe);
- }
- PausableBufferedObservable.prototype.pause = function () {
- this.controller.onNext(false);
- };
- PausableBufferedObservable.prototype.resume = function () {
- this.controller.onNext(true);
- };
- return PausableBufferedObservable;
- }(Observable));
- /**
- * Pauses the underlying observable sequence based upon the observable sequence which yields true/false,
- * and yields the values that were buffered while paused.
- * @example
- * var pauser = new Rx.Subject();
- * var source = Rx.Observable.interval(100).pausableBuffered(pauser);
- * @param {Observable} pauser The observable sequence used to pause the underlying sequence.
- * @returns {Observable} The observable sequence which is paused based upon the pauser.
- */
- observableProto.pausableBuffered = function (subject) {
- return new PausableBufferedObservable(this, subject);
- };
-
- /**
- * Attaches a controller to the observable sequence with the ability to queue.
- * @example
- * var source = Rx.Observable.interval(100).controlled();
- * source.request(3); // Reads 3 values
- * @param {Observable} pauser The observable sequence used to pause the underlying sequence.
- * @returns {Observable} The observable sequence which is paused based upon the pauser.
- */
- observableProto.controlled = function (enableQueue) {
- if (enableQueue == null) { enableQueue = true; }
- return new ControlledObservable(this, enableQueue);
- };
-
- var ControlledObservable = (function (_super) {
-
- inherits(ControlledObservable, _super);
-
- function subscribe (observer) {
- return this.source.subscribe(observer);
- }
-
- function ControlledObservable (source, enableQueue) {
- _super.call(this, subscribe);
- this.subject = new ControlledSubject(enableQueue);
- this.source = source.multicast(this.subject).refCount();
- }
-
- ControlledObservable.prototype.request = function (numberOfItems) {
- if (numberOfItems == null) { numberOfItems = -1; }
- return this.subject.request(numberOfItems);
- };
-
- return ControlledObservable;
-
- }(Observable));
-
- var ControlledSubject = Rx.ControlledSubject = (function (_super) {
-
- function subscribe (observer) {
- return this.subject.subscribe(observer);
- }
-
- inherits(ControlledSubject, _super);
-
- function ControlledSubject(enableQueue) {
- if (enableQueue == null) {
- enableQueue = true;
- }
-
- _super.call(this, subscribe);
- this.subject = new Subject();
- this.enableQueue = enableQueue;
- this.queue = enableQueue ? [] : null;
- this.requestedCount = 0;
- this.requestedDisposable = disposableEmpty;
- this.error = null;
- this.hasFailed = false;
- this.hasCompleted = false;
- this.controlledDisposable = disposableEmpty;
- }
-
- addProperties(ControlledSubject.prototype, Observer, {
- onCompleted: function () {
- checkDisposed.call(this);
- this.hasCompleted = true;
-
- if (!this.enableQueue || this.queue.length === 0) {
- this.subject.onCompleted();
- }
- },
- onError: function (error) {
- checkDisposed.call(this);
- this.hasFailed = true;
- this.error = error;
-
- if (!this.enableQueue || this.queue.length === 0) {
- this.subject.onError(error);
- }
- },
- onNext: function (value) {
- checkDisposed.call(this);
- var hasRequested = false;
-
- if (this.requestedCount === 0) {
- if (this.enableQueue) {
- this.queue.push(value);
- }
- } else {
- if (this.requestedCount !== -1) {
- if (this.requestedCount-- === 0) {
- this.disposeCurrentRequest();
- }
- }
- hasRequested = true;
- }
-
- if (hasRequested) {
- this.subject.onNext(value);
- }
- },
- _processRequest: function (numberOfItems) {
- if (this.enableQueue) {
- //console.log('queue length', this.queue.length);
-
- while (this.queue.length >= numberOfItems && numberOfItems > 0) {
- //console.log('number of items', numberOfItems);
- this.subject.onNext(this.queue.shift());
- numberOfItems--;
- }
-
- if (this.queue.length !== 0) {
- return { numberOfItems: numberOfItems, returnValue: true };
- } else {
- return { numberOfItems: numberOfItems, returnValue: false };
- }
- }
-
- if (this.hasFailed) {
- this.subject.onError(this.error);
- this.controlledDisposable.dispose();
- this.controlledDisposable = disposableEmpty;
- } else if (this.hasCompleted) {
- this.subject.onCompleted();
- this.controlledDisposable.dispose();
- this.controlledDisposable = disposableEmpty;
- }
-
- return { numberOfItems: numberOfItems, returnValue: false };
- },
- request: function (number) {
- checkDisposed.call(this);
- this.disposeCurrentRequest();
- var self = this,
- r = this._processRequest(number);
-
- number = r.numberOfItems;
- if (!r.returnValue) {
- this.requestedCount = number;
- this.requestedDisposable = disposableCreate(function () {
- self.requestedCount = 0;
- });
-
- return this.requestedDisposable
- } else {
- return disposableEmpty;
- }
- },
- disposeCurrentRequest: function () {
- this.requestedDisposable.dispose();
- this.requestedDisposable = disposableEmpty;
- },
-
- dispose: function () {
- this.isDisposed = true;
- this.error = null;
- this.subject.dispose();
- this.requestedDisposable.dispose();
- }
- });
-
- return ControlledSubject;
- }(Observable));
-
- return Rx;
- }));