es6/operator/bufferToggle.js
import { Subscription } from '../Subscription';
import { subscribeToResult } from '../util/subscribeToResult';
import { OuterSubscriber } from '../OuterSubscriber';
/**
* 缓冲源 Observable 的值,`openings` 发送的时候开始缓冲,`closingSelector` 发送的时候结束缓冲。
*
* <span class="informal">将过往数据收集到数组中. 当`opening`发送的时候开始收集, 然后调用`closingSelector`
* 函数获取 Observable ,该Observable 告知什么时候关闭缓冲。</span>
*
* <img src="./img/bufferToggle.png" width="100%">
*
* 缓冲源Observable的值,当`openings`Observable发出信号的时候开始缓冲数据, 当`closingSelector`返回的Subscribable
* 或者Promise发送的时候结束并且发送缓冲区.
*
* @example <caption>每隔一秒钟,发出接下来500毫秒内的点击事件。</caption>
* var clicks = Rx.Observable.fromEvent(document, 'click');
* var openings = Rx.Observable.interval(1000);
* var buffered = clicks.bufferToggle(openings, i =>
* i % 2 ? Rx.Observable.interval(500) : Rx.Observable.empty()
* );
* buffered.subscribe(x => console.log(x));
*
* @see {@link buffer}
* @see {@link bufferCount}
* @see {@link bufferTime}
* @see {@link bufferWhen}
* @see {@link windowToggle}
*
* @param {SubscribableOrPromise<O>} openings 开启新缓冲区的通知,可以是 Subscribable 或 Promise 。
* @param {function(value: O): SubscribableOrPromise} closingSelector 接受`openings`observable
* 发出的数据返回一个可以被订阅的对象或者Promise的函数,当它发出时,会发信号给相关的缓冲区以通知它们应该发出并清理。
* @return {Observable<T[]>} 缓冲数组的 observable。
* @method bufferToggle
* @owner Observable
*/
export function bufferToggle(openings, closingSelector) {
return this.lift(new BufferToggleOperator(openings, closingSelector));
}
class BufferToggleOperator {
constructor(openings, closingSelector) {
this.openings = openings;
this.closingSelector = closingSelector;
}
call(subscriber, source) {
return source.subscribe(new BufferToggleSubscriber(subscriber, this.openings, this.closingSelector));
}
}
/**
* We need this JSDoc comment for affecting ESDoc.
* @ignore
* @extends {Ignored}
*/
class BufferToggleSubscriber extends OuterSubscriber {
constructor(destination, openings, closingSelector) {
super(destination);
this.openings = openings;
this.closingSelector = closingSelector;
this.contexts = [];
this.add(subscribeToResult(this, openings));
}
_next(value) {
const contexts = this.contexts;
const len = contexts.length;
for (let i = 0; i < len; i++) {
contexts[i].buffer.push(value);
}
}
_error(err) {
const contexts = this.contexts;
while (contexts.length > 0) {
const context = contexts.shift();
context.subscription.unsubscribe();
context.buffer = null;
context.subscription = null;
}
this.contexts = null;
super._error(err);
}
_complete() {
const contexts = this.contexts;
while (contexts.length > 0) {
const context = contexts.shift();
this.destination.next(context.buffer);
context.subscription.unsubscribe();
context.buffer = null;
context.subscription = null;
}
this.contexts = null;
super._complete();
}
notifyNext(outerValue, innerValue, outerIndex, innerIndex, innerSub) {
outerValue ? this.closeBuffer(outerValue) : this.openBuffer(innerValue);
}
notifyComplete(innerSub) {
this.closeBuffer(innerSub.context);
}
openBuffer(value) {
try {
const closingSelector = this.closingSelector;
const closingNotifier = closingSelector.call(this, value);
if (closingNotifier) {
this.trySubscribe(closingNotifier);
}
}
catch (err) {
this._error(err);
}
}
closeBuffer(context) {
const contexts = this.contexts;
if (contexts && context) {
const { buffer, subscription } = context;
this.destination.next(buffer);
contexts.splice(contexts.indexOf(context), 1);
this.remove(subscription);
subscription.unsubscribe();
}
}
trySubscribe(closingNotifier) {
const contexts = this.contexts;
const buffer = [];
const subscription = new Subscription();
const context = { buffer, subscription };
contexts.push(context);
const innerSubscription = subscribeToResult(this, closingNotifier, context);
if (!innerSubscription || innerSubscription.closed) {
this.closeBuffer(context);
}
else {
innerSubscription.context = context;
this.add(innerSubscription);
subscription.add(innerSubscription);
}
}
}
//# sourceMappingURL=bufferToggle.js.map