es6/operator/takeLast.js
import { Subscriber } from '../Subscriber';
import { ArgumentOutOfRangeError } from '../util/ArgumentOutOfRangeError';
import { EmptyObservable } from '../observable/EmptyObservable';
/**
* 只发出源 Observable 最后发出的的N个值 (N = `count`)。
*
* <span class="informal">记住源 Observable 的最后N个值 (N = `count`),然后只有当
* 它完成时发出这些值。</span>
*
* <img src="./img/takeLast.png" width="100%">
*
* `takeLast` 返回的 Observable 只发出源 Observable 最后发出的的N个值 (N = `count`)。
* 如果源发出值的数量小于 `count` 的话,那么它的所有值都将发出。此操作符必须等待
* 源 Observable 的 `complete` 通知发送才能在输出 Observable 上发出 `next` 值,
* 因为不这样的话它无法知道源 Observable 上是否还有更多值要发出。出于这个原因,
* 所有值都将同步发出,然后是 `complete` 通知。
*
* @example <caption>获取有多个值的 Observable 的最后3个值</caption>
* var many = Rx.Observable.range(1, 100);
* var lastThree = many.takeLast(3);
* lastThree.subscribe(x => console.log(x));
*
* @see {@link take}
* @see {@link takeUntil}
* @see {@link takeWhile}
* @see {@link skip}
*
* @throws {ArgumentOutOfRangeError} 当使用 `takeLast(i)` 时,如果 `i < 0`,
* 它会发送 ArgumentOutOrRangeError 给观察者的 `error` 回调函数。
*
* @param {number} count 从源 Observable 的值序列的末尾处,要发出的值的最大数量。
* @return {Observable<T>} 该 Observable 只发出源 Observable 最后发出的的N个值 (N = `count`),
* 或者发出源 Observable 的所有值,如果源发出值的数量小于 `count` 的话。
* @method takeLast
* @owner Observable
*/
export function takeLast(count) {
if (count === 0) {
return new EmptyObservable();
}
else {
return this.lift(new TakeLastOperator(count));
}
}
class TakeLastOperator {
constructor(total) {
this.total = total;
if (this.total < 0) {
throw new ArgumentOutOfRangeError;
}
}
call(subscriber, source) {
return source.subscribe(new TakeLastSubscriber(subscriber, this.total));
}
}
/**
* We need this JSDoc comment for affecting ESDoc.
* @ignore
* @extends {Ignored}
*/
class TakeLastSubscriber extends Subscriber {
constructor(destination, total) {
super(destination);
this.total = total;
this.ring = new Array();
this.count = 0;
}
_next(value) {
const ring = this.ring;
const total = this.total;
const count = this.count++;
if (ring.length < total) {
ring.push(value);
}
else {
const index = count % total;
ring[index] = value;
}
}
_complete() {
const destination = this.destination;
let count = this.count;
if (count > 0) {
const total = this.count >= this.total ? this.total : this.count;
const ring = this.ring;
for (let i = 0; i < total; i++) {
const idx = (count++) % total;
destination.next(ring[idx]);
}
}
destination.complete();
}
}
//# sourceMappingURL=takeLast.js.map