Skip to content

Commit b109100

Browse files
kwonojbenlesh
authored andcommitted
fix(delay): accepts absolute time delay
- delay operator accepts absolute time as well as relative time - add additional test coverages relates to #549
1 parent f67a596 commit b109100

File tree

2 files changed

+129
-53
lines changed

2 files changed

+129
-53
lines changed

spec/operators/delay-spec.js

+89-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,96 @@
1-
/* globals describe, it, expect, expectObservable, hot, rxTestScheduler */
1+
/* globals describe, it, expect, expectObservable, expectSubscriptions, hot, rxTestScheduler */
22
var Rx = require('../../dist/cjs/Rx');
3+
var Observable = Rx.Observable;
34

45
describe('Observable.prototype.delay()', function () {
56
it('should delay by specified timeframe', function () {
6-
var source = hot('--a--|');
7-
var expected = '-----a--|';
7+
var e1 = hot('--a--b--|');
8+
var expected = '-----a--b--|';
9+
var subs = '^ !';
810

9-
expectObservable(source.delay(30, rxTestScheduler)).toBe(expected);
11+
expectObservable(e1.delay(30, rxTestScheduler)).toBe(expected);
12+
expectSubscriptions(e1.subscriptions).toBe(subs);
13+
});
14+
15+
it('should delay by absolute time period', function () {
16+
var e1 = hot('--a--b--|');
17+
var expected = '-----a--b--|';
18+
var subs = '^ !';
19+
var absoluteDelay = new Date(rxTestScheduler.now() + 30);
20+
21+
expectObservable(e1.delay(absoluteDelay, rxTestScheduler)).toBe(expected);
22+
expectSubscriptions(e1.subscriptions).toBe(subs);
23+
});
24+
25+
it('should delay by absolute time period after subscription', function () {
26+
var e1 = hot('---^--a--b--|');
27+
var expected = '------a--b--|';
28+
var subs = '^ !';
29+
var absoluteDelay = new Date(rxTestScheduler.now() + 30);
30+
31+
expectObservable(e1.delay(absoluteDelay, rxTestScheduler)).toBe(expected);
32+
expectSubscriptions(e1.subscriptions).toBe(subs);
33+
});
34+
35+
it('should raise error when source raises error', function () {
36+
var e1 = hot('---a---b---#');
37+
var expected = '------a---b#';
38+
var subs = '^ !';
39+
40+
expectObservable(e1.delay(30, rxTestScheduler)).toBe(expected);
41+
expectSubscriptions(e1.subscriptions).toBe(subs);
42+
});
43+
44+
it('should raise error when source raises error', function () {
45+
var e1 = hot('--a--b--#');
46+
var expected = '-----a--#';
47+
var subs = '^ !';
48+
var absoluteDelay = new Date(rxTestScheduler.now() + 30);
49+
50+
expectObservable(e1.delay(absoluteDelay, rxTestScheduler)).toBe(expected);
51+
expectSubscriptions(e1.subscriptions).toBe(subs);
52+
});
53+
54+
it('should raise error when source raises error after subscription', function () {
55+
var e1 = hot('---^---a---b---#');
56+
var expected = '-------a---b#';
57+
var e1Sub = '^ !';
58+
var absoluteDelay = new Date(rxTestScheduler.now() + 30);
59+
60+
expectObservable(e1.delay(absoluteDelay, rxTestScheduler)).toBe(expected);
61+
expectSubscriptions(e1.subscriptions).toBe(e1Sub);
62+
});
63+
64+
it('should delay when source does not emits', function () {
65+
var e1 = hot('----|');
66+
var expected = '-------|';
67+
var subs = '^ !';
68+
69+
expectObservable(e1.delay(30, rxTestScheduler)).toBe(expected);
70+
expectSubscriptions(e1.subscriptions).toBe(subs);
71+
});
72+
73+
it('should delay when source is empty', function () {
74+
var e1 = Observable.empty();
75+
var expected = '---|';
76+
77+
expectObservable(e1.delay(30, rxTestScheduler)).toBe(expected);
78+
});
79+
80+
it('should not complete when source does not completes', function () {
81+
var e1 = hot('---a---b-');
82+
var expected = '------a---b-';
83+
var unsub = '----------------!';
84+
var subs = '^ !';
85+
86+
expectObservable(e1.delay(30, rxTestScheduler), unsub).toBe(expected);
87+
expectSubscriptions(e1.subscriptions).toBe(subs);
88+
});
89+
90+
it('should not complete when source never completes', function () {
91+
var e1 = Observable.never();
92+
var expected = '-';
93+
94+
expectObservable(e1.delay(30, rxTestScheduler)).toBe(expected);
1095
});
1196
});

src/operators/delay.ts

+40-49
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,20 @@
11
import Operator from '../Operator';
2-
import Observer from '../Observer';
32
import Scheduler from '../Scheduler';
43
import Subscriber from '../Subscriber';
54
import Notification from '../Notification';
65
import immediate from '../schedulers/immediate';
6+
import isDate from '../util/isDate';
77

8-
export default function delay<T>(delay: number, scheduler: Scheduler = immediate) {
9-
return this.lift(new DelayOperator(delay, scheduler));
8+
export default function delay<T>(delay: number|Date,
9+
scheduler: Scheduler = immediate) {
10+
let absoluteDelay = isDate(delay);
11+
let delayFor = absoluteDelay ? (+delay - scheduler.now()) : <number>delay;
12+
return this.lift(new DelayOperator(delayFor, scheduler));
1013
}
1114

1215
class DelayOperator<T, R> implements Operator<T, R> {
13-
14-
delay: number;
15-
scheduler: Scheduler;
16-
17-
constructor(delay: number, scheduler: Scheduler) {
18-
this.delay = delay;
19-
this.scheduler = scheduler;
16+
constructor(private delay: number,
17+
private scheduler: Scheduler) {
2018
}
2119

2220
call(subscriber: Subscriber<T>): Subscriber<T> {
@@ -25,21 +23,20 @@ class DelayOperator<T, R> implements Operator<T, R> {
2523
}
2624

2725
class DelaySubscriber<T> extends Subscriber<T> {
26+
private queue: Array<any> = [];
27+
private active: boolean = false;
28+
private errored: boolean = false;
2829

29-
protected delay: number;
30-
protected queue: Array<any> = [];
31-
protected scheduler: Scheduler;
32-
protected active: boolean = false;
33-
protected errored: boolean = false;
34-
35-
static dispatch(state) {
30+
private static dispatch(state): void {
3631
const source = state.source;
3732
const queue = source.queue;
3833
const scheduler = state.scheduler;
3934
const destination = state.destination;
35+
4036
while (queue.length > 0 && (queue[0].time - scheduler.now()) <= 0) {
4137
queue.shift().notification.observe(destination);
4238
}
39+
4340
if (queue.length > 0) {
4441
let delay = Math.max(0, queue[0].time - scheduler.now());
4542
(<any> this).schedule(state, delay);
@@ -48,56 +45,50 @@ class DelaySubscriber<T> extends Subscriber<T> {
4845
}
4946
}
5047

51-
constructor(destination: Subscriber<T>, delay: number, scheduler: Scheduler) {
48+
constructor(destination: Subscriber<T>,
49+
private delay: number,
50+
private scheduler: Scheduler) {
5251
super(destination);
53-
this.delay = delay;
54-
this.scheduler = scheduler;
5552
}
5653

57-
_next(x) {
58-
if (this.errored) {
54+
private _schedule(scheduler: Scheduler): void {
55+
this.active = true;
56+
this.add(scheduler.schedule(DelaySubscriber.dispatch, this.delay, {
57+
source: this, destination: this.destination, scheduler: scheduler
58+
}));
59+
}
60+
61+
private scheduleNotification(notification: Notification<any>): void {
62+
if (this.errored === true) {
5963
return;
6064
}
65+
6166
const scheduler = this.scheduler;
62-
this.queue.push(new DelayMessage<T>(scheduler.now() + this.delay, Notification.createNext(x)));
67+
let message = new DelayMessage<T>(scheduler.now() + this.delay, notification);
68+
this.queue.push(message);
69+
6370
if (this.active === false) {
6471
this._schedule(scheduler);
6572
}
6673
}
6774

68-
_error(e) {
69-
const scheduler = this.scheduler;
70-
this.errored = true;
71-
this.queue = [new DelayMessage<T>(scheduler.now() + this.delay, Notification.createError(e))];
72-
if (this.active === false) {
73-
this._schedule(scheduler);
74-
}
75+
_next(value: T) {
76+
this.scheduleNotification(Notification.createNext(value));
7577
}
7678

77-
_complete() {
78-
if (this.errored) {
79-
return;
80-
}
81-
const scheduler = this.scheduler;
82-
this.queue.push(new DelayMessage<T>(scheduler.now() + this.delay, Notification.createComplete()));
83-
if (this.active === false) {
84-
this._schedule(scheduler);
85-
}
79+
_error(err) {
80+
this.errored = true;
81+
this.queue = [];
82+
this.destination.error(err);
8683
}
8784

88-
_schedule(scheduler) {
89-
this.active = true;
90-
this.add(scheduler.schedule(DelaySubscriber.dispatch, this.delay, {
91-
source: this, destination: this.destination, scheduler: scheduler
92-
}));
85+
_complete() {
86+
this.scheduleNotification(Notification.createComplete());
9387
}
9488
}
9589

9690
class DelayMessage<T> {
97-
time: number;
98-
notification: any;
99-
constructor(time: number, notification: any) {
100-
this.time = time;
101-
this.notification = notification;
91+
constructor(private time: number,
92+
private notification: any) {
10293
}
10394
}

0 commit comments

Comments
 (0)