Skip to content

Commit 1d735b9

Browse files
committed
feat(operator): add throttle
closes #191
1 parent 9156d61 commit 1d735b9

File tree

5 files changed

+95
-0
lines changed

5 files changed

+95
-0
lines changed

Diff for: spec/operators/throttle-spec.js

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/* globals describe, it, expect */
2+
var Rx = require('../../dist/cjs/Rx');
3+
var Observable = Rx.Observable;
4+
var Scheduler = Rx.Scheduler;
5+
6+
describe('Observable.prototype.throttle()', function () {
7+
it('should delay calls by the specified amount', function (done) {
8+
var expected = [3, 4];
9+
var source = Observable.concat(Observable.value(1),
10+
Observable.timer(10).mapTo(2),
11+
Observable.timer(10).mapTo(3),
12+
Observable.timer(100).mapTo(4)
13+
)
14+
.throttle(50)
15+
.subscribe(function (x) {
16+
expect(x).toBe(expected.shift());
17+
}, null, done);
18+
});
19+
});

Diff for: spec/scheduler-spec.js

+16
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,20 @@ describe('Scheduler.immediate', function() {
1717
expect(call1).toBe(true);
1818
expect(call2).toBe(true);
1919
});
20+
21+
it('should schedule things in the future too', function (done) {
22+
var called = false;
23+
Scheduler.immediate.schedule(500, null, function () {
24+
called = true;
25+
});
26+
27+
setTimeout(function () {
28+
expect(called).toBe(false);
29+
}, 400);
30+
31+
setTimeout(function() {
32+
expect(called).toBe(true);
33+
done();
34+
}, 700);
35+
})
2036
});

Diff for: src/Observable.ts

+1
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ export default class Observable<T> {
147147
// HACK: this should be Observable<Notification<T>>, but the build process didn't like it. :(
148148
// this will be fixed when we can move everything to the TypeScript compiler I suspect.
149149
materialize: () => Observable<any>;
150+
throttle: (delay: number, scheduler?: Scheduler) => Observable<T>;
150151

151152
observeOn: (scheduler: Scheduler, delay?: number) => Observable<T>;
152153
subscribeOn: (scheduler: Scheduler, delay?: number) => Observable<T>;

Diff for: src/Rx.ts

+4
Original file line numberDiff line numberDiff line change
@@ -162,9 +162,13 @@ import groupBy from './operators/groupBy';
162162
observableProto.groupBy = groupBy;
163163

164164
import delay from './operators/delay';
165+
import throttle from './operators/throttle';
166+
165167
observableProto.delay = delay;
168+
observableProto.throttle = throttle;
166169

167170
export {
171+
168172
Subject,
169173
Scheduler,
170174
Observable,

Diff for: src/operators/throttle.ts

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import Operator from '../Operator';
2+
import Observer from '../Observer';
3+
import Subscriber from '../Subscriber';
4+
import Observable from '../Observable';
5+
import Scheduler from '../Scheduler';
6+
import Subscription from '../Subscription';
7+
8+
import tryCatch from '../util/tryCatch';
9+
import {errorObject} from '../util/errorObject';
10+
import bindCallback from '../util/bindCallback';
11+
12+
export default function throttle<T>(delay: number, scheduler: Scheduler = Scheduler.nextTick) {
13+
return this.lift(new ThrottleOperator(delay, scheduler));
14+
}
15+
16+
export class ThrottleOperator<T, R> extends Operator<T, R> {
17+
constructor(private delay:number, private scheduler:Scheduler) {
18+
super();
19+
}
20+
21+
call(observer: Observer<R>): Observer<T> {
22+
return new ThrottleSubscriber(observer, this.delay, this.scheduler);
23+
}
24+
}
25+
26+
export class ThrottleSubscriber<T, R> extends Subscriber<T> {
27+
private throttled: Subscription<any>;
28+
29+
constructor(destination:Observer<T>, private delay:number, private scheduler:Scheduler) {
30+
super(destination);
31+
}
32+
33+
_next(x) {
34+
this.clearThrottle();
35+
this.add(this.throttled = this.scheduler.schedule(this.delay, { value: x, subscriber: this }, dispatchNext));
36+
}
37+
38+
throttledNext(x) {
39+
this.clearThrottle();
40+
this.destination.next(x);
41+
}
42+
43+
clearThrottle() {
44+
const throttled = this.throttled;
45+
if (throttled) {
46+
this.remove(throttled);
47+
throttled.unsubscribe();
48+
this.throttled = null;
49+
}
50+
}
51+
}
52+
53+
function dispatchNext({ value, subscriber }) {
54+
subscriber.throttledNext(value);
55+
}

0 commit comments

Comments
 (0)