From 8c73e6ea01db7200df19ec9bf9967a80b1ddd394 Mon Sep 17 00:00:00 2001 From: Jason Aden Date: Wed, 6 Sep 2017 13:52:29 -0700 Subject: [PATCH] feat(sample): add higher-order lettable version of sample --- src/operator/sample.ts | 53 +----------------------- src/operators/index.ts | 1 + src/operators/sample.ts | 91 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+), 51 deletions(-) create mode 100644 src/operators/sample.ts diff --git a/src/operator/sample.ts b/src/operator/sample.ts index 081ba2cad7..a9cef87335 100644 --- a/src/operator/sample.ts +++ b/src/operator/sample.ts @@ -1,10 +1,5 @@ -import { Operator } from '../Operator'; import { Observable } from '../Observable'; -import { Subscriber } from '../Subscriber'; -import { TeardownLogic } from '../Subscription'; -import { OuterSubscriber } from '../OuterSubscriber'; -import { InnerSubscriber } from '../InnerSubscriber'; -import { subscribeToResult } from '../util/subscribeToResult'; +import { sample as higherOrder } from '../operators/sample'; /** * Emits the most recently emitted value from the source Observable whenever @@ -41,49 +36,5 @@ import { subscribeToResult } from '../util/subscribeToResult'; * @owner Observable */ export function sample(this: Observable, notifier: Observable): Observable { - return this.lift(new SampleOperator(notifier)); -} - -class SampleOperator implements Operator { - constructor(private notifier: Observable) { - } - - call(subscriber: Subscriber, source: any): TeardownLogic { - const sampleSubscriber = new SampleSubscriber(subscriber); - const subscription = source.subscribe(sampleSubscriber); - subscription.add(subscribeToResult(sampleSubscriber, this.notifier)); - return subscription; - } -} - -/** - * We need this JSDoc comment for affecting ESDoc. - * @ignore - * @extends {Ignored} - */ -class SampleSubscriber extends OuterSubscriber { - private value: T; - private hasValue: boolean = false; - - protected _next(value: T) { - this.value = value; - this.hasValue = true; - } - - notifyNext(outerValue: T, innerValue: R, - outerIndex: number, innerIndex: number, - innerSub: InnerSubscriber): void { - this.emitValue(); - } - - notifyComplete(): void { - this.emitValue(); - } - - emitValue() { - if (this.hasValue) { - this.hasValue = false; - this.destination.next(this.value); - } - } + return higherOrder(notifier)(this); } diff --git a/src/operators/index.ts b/src/operators/index.ts index b68d14e5cb..92f383ab48 100644 --- a/src/operators/index.ts +++ b/src/operators/index.ts @@ -58,6 +58,7 @@ export { repeatWhen } from './repeatWhen'; export { retry } from './retry'; export { retryWhen } from './retryWhen'; export { refCount } from './refCount'; +export { sample } from './sample'; export { scan } from './scan'; export { subscribeOn } from './subscribeOn'; export { switchAll } from './switchAll'; diff --git a/src/operators/sample.ts b/src/operators/sample.ts new file mode 100644 index 0000000000..619e4f94d8 --- /dev/null +++ b/src/operators/sample.ts @@ -0,0 +1,91 @@ +import { Operator } from '../Operator'; +import { Observable } from '../Observable'; +import { Subscriber } from '../Subscriber'; +import { TeardownLogic } from '../Subscription'; +import { OuterSubscriber } from '../OuterSubscriber'; +import { InnerSubscriber } from '../InnerSubscriber'; +import { subscribeToResult } from '../util/subscribeToResult'; + +import { MonoTypeOperatorFunction } from '../interfaces'; + +/** + * Emits the most recently emitted value from the source Observable whenever + * another Observable, the `notifier`, emits. + * + * It's like {@link sampleTime}, but samples whenever + * the `notifier` Observable emits something. + * + * + * + * Whenever the `notifier` Observable emits a value or completes, `sample` + * looks at the source Observable and emits whichever value it has most recently + * emitted since the previous sampling, unless the source has not emitted + * anything since the previous sampling. The `notifier` is subscribed to as soon + * as the output Observable is subscribed. + * + * @example On every click, sample the most recent "seconds" timer + * var seconds = Rx.Observable.interval(1000); + * var clicks = Rx.Observable.fromEvent(document, 'click'); + * var result = seconds.sample(clicks); + * result.subscribe(x => console.log(x)); + * + * @see {@link audit} + * @see {@link debounce} + * @see {@link sampleTime} + * @see {@link throttle} + * + * @param {Observable} notifier The Observable to use for sampling the + * source Observable. + * @return {Observable} An Observable that emits the results of sampling the + * values emitted by the source Observable whenever the notifier Observable + * emits value or completes. + * @method sample + * @owner Observable + */ +export function sample(notifier: Observable): MonoTypeOperatorFunction { + return (source: Observable) => source.lift(new SampleOperator(notifier)); +} + +class SampleOperator implements Operator { + constructor(private notifier: Observable) { + } + + call(subscriber: Subscriber, source: any): TeardownLogic { + const sampleSubscriber = new SampleSubscriber(subscriber); + const subscription = source.subscribe(sampleSubscriber); + subscription.add(subscribeToResult(sampleSubscriber, this.notifier)); + return subscription; + } +} + +/** + * We need this JSDoc comment for affecting ESDoc. + * @ignore + * @extends {Ignored} + */ +class SampleSubscriber extends OuterSubscriber { + private value: T; + private hasValue: boolean = false; + + protected _next(value: T) { + this.value = value; + this.hasValue = true; + } + + notifyNext(outerValue: T, innerValue: R, + outerIndex: number, innerIndex: number, + innerSub: InnerSubscriber): void { + this.emitValue(); + } + + notifyComplete(): void { + this.emitValue(); + } + + emitValue() { + if (this.hasValue) { + this.hasValue = false; + this.destination.next(this.value); + } + } +}