Bones/node_modules/rx/dist/rx.backpressure.js

570 lines
17 KiB
JavaScript
Raw Normal View History

2017-05-17 13:45:25 -04:00
// 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,
AbstractObserver = Rx.internals.AbstractObserver,
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,
currentThreadScheduler = Rx.Scheduler.currentThread,
identity = Rx.helpers.identity;
var objectDisposed = 'Object has been disposed';
function checkDisposed() { if (this.isDisposed) { throw new Error(objectDisposed); } }
/**
* Used to pause and resume streams.
*/
Rx.Pauser = (function (__super__) {
inherits(Pauser, __super__);
function Pauser() {
__super__.call(this);
}
/**
* Pauses the underlying sequence.
*/
Pauser.prototype.pause = function () { this.onNext(false); };
/**
* Resumes the underlying sequence.
*/
Pauser.prototype.resume = function () { this.onNext(true); };
return Pauser;
}(Subject));
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, source);
}
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 (o) {
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) {
o.onError(err);
return;
}
try {
res = resultSelector.apply(null, values);
} catch (ex) {
o.onError(ex);
return;
}
o.onNext(res);
}
if (isDone && values[1]) {
o.onCompleted();
}
}
return new CompositeDisposable(
source.subscribe(
function (x) {
next(x, 0);
},
function (e) {
if (values[1]) {
o.onError(e);
} else {
err = e;
}
},
function () {
isDone = true;
values[1] && o.onCompleted();
}),
subject.subscribe(
function (x) {
next(x, 1);
},
function (e) { o.onError(e); },
function () {
isDone = true;
next(true, 1);
})
);
}, source);
}
var PausableBufferedObservable = (function (__super__) {
inherits(PausableBufferedObservable, __super__);
function subscribe(o) {
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) {
o.onNext(q.shift());
}
}
} else {
previousShouldFire = results.shouldFire;
// new data
if (results.shouldFire) {
o.onNext(results.data);
} else {
q.push(results.data);
}
}
},
function (err) {
// Empty buffer before sending error
while (q.length > 0) {
o.onNext(q.shift());
}
o.onError(err);
},
function () {
// Empty buffer before sending completion
while (q.length > 0) {
o.onNext(q.shift());
}
o.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, source);
}
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);
};
var ControlledObservable = (function (__super__) {
inherits(ControlledObservable, __super__);
function subscribe (observer) {
return this.source.subscribe(observer);
}
function ControlledObservable (source, enableQueue) {
__super__.call(this, subscribe, source);
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 = (function (__super__) {
function subscribe (observer) {
return this.subject.subscribe(observer);
}
inherits(ControlledSubject, __super__);
function ControlledSubject(enableQueue) {
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 () {
this.hasCompleted = true;
(!this.enableQueue || this.queue.length === 0) && this.subject.onCompleted();
},
onError: function (error) {
this.hasFailed = true;
this.error = error;
(!this.enableQueue || this.queue.length === 0) && this.subject.onError(error);
},
onNext: function (value) {
var hasRequested = false;
if (this.requestedCount === 0) {
this.enableQueue && this.queue.push(value);
} else {
(this.requestedCount !== -1 && this.requestedCount-- === 0) && this.disposeCurrentRequest();
hasRequested = true;
}
hasRequested && this.subject.onNext(value);
},
_processRequest: function (numberOfItems) {
if (this.enableQueue) {
while (this.queue.length >= numberOfItems && numberOfItems > 0) {
this.subject.onNext(this.queue.shift());
numberOfItems--;
}
return this.queue.length !== 0 ?
{ numberOfItems: numberOfItems, returnValue: true } :
{ 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) {
this.disposeCurrentRequest();
var self = this, r = this._processRequest(number);
var 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;
}
});
return ControlledSubject;
}(Observable));
/**
* 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 StopAndWaitObservable = (function (__super__) {
function subscribe (observer) {
this.subscription = this.source.subscribe(new StopAndWaitObserver(observer, this, this.subscription));
var self = this;
timeoutScheduler.schedule(function () { self.source.request(1); });
return this.subscription;
}
inherits(StopAndWaitObservable, __super__);
function StopAndWaitObservable (source) {
__super__.call(this, subscribe, source);
this.source = source;
}
var StopAndWaitObserver = (function (__sub__) {
inherits(StopAndWaitObserver, __sub__);
function StopAndWaitObserver (observer, observable, cancel) {
__sub__.call(this);
this.observer = observer;
this.observable = observable;
this.cancel = cancel;
}
var stopAndWaitObserverProto = StopAndWaitObserver.prototype;
stopAndWaitObserverProto.completed = function () {
this.observer.onCompleted();
this.dispose();
};
stopAndWaitObserverProto.error = function (error) {
this.observer.onError(error);
this.dispose();
}
stopAndWaitObserverProto.next = function (value) {
this.observer.onNext(value);
var self = this;
timeoutScheduler.schedule(function () {
self.observable.source.request(1);
});
};
stopAndWaitObserverProto.dispose = function () {
this.observer = null;
if (this.cancel) {
this.cancel.dispose();
this.cancel = null;
}
__sub__.prototype.dispose.call(this);
};
return StopAndWaitObserver;
}(AbstractObserver));
return StopAndWaitObservable;
}(Observable));
/**
* Attaches a stop and wait observable to the current observable.
* @returns {Observable} A stop and wait observable.
*/
ControlledObservable.prototype.stopAndWait = function () {
return new StopAndWaitObservable(this);
};
var WindowedObservable = (function (__super__) {
function subscribe (observer) {
this.subscription = this.source.subscribe(new WindowedObserver(observer, this, this.subscription));
var self = this;
timeoutScheduler.schedule(function () {
self.source.request(self.windowSize);
});
return this.subscription;
}
inherits(WindowedObservable, __super__);
function WindowedObservable(source, windowSize) {
__super__.call(this, subscribe, source);
this.source = source;
this.windowSize = windowSize;
}
var WindowedObserver = (function (__sub__) {
inherits(WindowedObserver, __sub__);
function WindowedObserver(observer, observable, cancel) {
this.observer = observer;
this.observable = observable;
this.cancel = cancel;
this.received = 0;
}
var windowedObserverPrototype = WindowedObserver.prototype;
windowedObserverPrototype.completed = function () {
this.observer.onCompleted();
this.dispose();
};
windowedObserverPrototype.error = function (error) {
this.observer.onError(error);
this.dispose();
};
windowedObserverPrototype.next = function (value) {
this.observer.onNext(value);
this.received = ++this.received % this.observable.windowSize;
if (this.received === 0) {
var self = this;
timeoutScheduler.schedule(function () {
self.observable.source.request(self.observable.windowSize);
});
}
};
windowedObserverPrototype.dispose = function () {
this.observer = null;
if (this.cancel) {
this.cancel.dispose();
this.cancel = null;
}
__sub__.prototype.dispose.call(this);
};
return WindowedObserver;
}(AbstractObserver));
return WindowedObservable;
}(Observable));
/**
* Creates a sliding windowed observable based upon the window size.
* @param {Number} windowSize The number of items in the window
* @returns {Observable} A windowed observable based upon the window size.
*/
ControlledObservable.prototype.windowed = function (windowSize) {
return new WindowedObservable(this, windowSize);
};
return Rx;
}));