From 2c43af7d76ac8944a7cbd7e86568395d52b0c919 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Thu, 31 May 2018 20:37:02 +0200 Subject: [PATCH] fix(delayWhen): Emit source value if duration selector completes synchronously (#3664) * fix(delayWhen): Emit source value if duration selector completes synchronously This fixes an issue where delayWhen would not re-emit a source emission if the duration selector completed synchronously. fixes #3663 * docs(delayWhen): Deprecate completion of notifier triggering source emission This deprecates the behavior that the completion of the notifier observable will cause the source emission to be emitted on the output observable. --- spec/operators/delayWhen-spec.ts | 24 +++++++++++++++++++++++- src/internal/operators/delayWhen.ts | 17 +++++++++-------- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/spec/operators/delayWhen-spec.ts b/spec/operators/delayWhen-spec.ts index bdc4021e9a..88b5f8ed5a 100644 --- a/spec/operators/delayWhen-spec.ts +++ b/spec/operators/delayWhen-spec.ts @@ -1,4 +1,4 @@ -import { of } from 'rxjs'; +import { of, EMPTY } from 'rxjs'; import { delayWhen } from 'rxjs/operators'; import { TestScheduler } from 'rxjs/testing'; import { hot, cold, expectObservable, expectSubscriptions } from '../helpers/marble-testing'; @@ -106,6 +106,28 @@ describe('delayWhen operator', () => { expectObservable(result).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(subs); expectSubscriptions(selector.subscriptions).toBe(selectorSubs); + }); + + it('should emit if the selector completes synchronously', () => { + const e1 = hot('a--|'); + const expected = 'a--|'; + const subs = '^ !'; + + const result = e1.pipe(delayWhen((x: any) => EMPTY)); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should emit if the source completes synchronously and the selector completes synchronously', () => { + const e1 = hot('(a|)'); + const expected = '(a|)'; + const subs = '(^!)'; + + const result = e1.pipe(delayWhen((x: any) => EMPTY)); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); }); it('should not emit if selector never emits', () => { diff --git a/src/internal/operators/delayWhen.ts b/src/internal/operators/delayWhen.ts index f2c0d4a702..113c1d7d7c 100644 --- a/src/internal/operators/delayWhen.ts +++ b/src/internal/operators/delayWhen.ts @@ -7,6 +7,12 @@ import { InnerSubscriber } from '../InnerSubscriber'; import { subscribeToResult } from '../util/subscribeToResult'; import { MonoTypeOperatorFunction, TeardownLogic } from '../types'; +/* tslint:disable:max-line-length */ +/** @deprecated In future versions, empty notifiers will no longer re-emit the source value on the output observable. */ +export function delayWhen(delayDurationSelector: (value: T) => Observable, subscriptionDelay?: Observable): MonoTypeOperatorFunction; +export function delayWhen(delayDurationSelector: (value: T) => Observable, subscriptionDelay?: Observable): MonoTypeOperatorFunction; +/* tslint:disable:max-line-length */ + /** * Delays the emission of items from the source Observable by a given time span * determined by the emissions of another Observable. @@ -22,6 +28,8 @@ import { MonoTypeOperatorFunction, TeardownLogic } from '../types'; * argument, and should return an Observable, called the "duration" Observable. * The source value is emitted on the output Observable only when the duration * Observable emits a value or completes. + * The completion of the notifier triggering the emission of the source value + * is deprecated behavior and will be removed in future versions. * * Optionally, `delayWhen` takes a second argument, `subscriptionDelay`, which * is an Observable. When `subscriptionDelay` emits its first value or @@ -79,7 +87,6 @@ class DelayWhenOperator implements Operator { class DelayWhenSubscriber extends OuterSubscriber { private completed: boolean = false; private delayNotifierSubscriptions: Array = []; - private values: Array = []; constructor(destination: Subscriber, private delayDurationSelector: (value: T) => Observable) { @@ -126,15 +133,11 @@ class DelayWhenSubscriber extends OuterSubscriber { subscription.unsubscribe(); const subscriptionIdx = this.delayNotifierSubscriptions.indexOf(subscription); - let value: T = null; - if (subscriptionIdx !== -1) { - value = this.values[subscriptionIdx]; this.delayNotifierSubscriptions.splice(subscriptionIdx, 1); - this.values.splice(subscriptionIdx, 1); } - return value; + return subscription.outerValue; } private tryDelay(delayNotifier: Observable, value: T): void { @@ -144,8 +147,6 @@ class DelayWhenSubscriber extends OuterSubscriber { this.add(notifierSubscription); this.delayNotifierSubscriptions.push(notifierSubscription); } - - this.values.push(value); } private tryComplete(): void {