Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 074546b

Browse files
authored
Merge pull request #363 from Urigo/feature/observable-throttle
Feature/observable throttle
2 parents 5e4e06f + cf25225 commit 074546b

6 files changed

Lines changed: 151 additions & 110 deletions

File tree

dist/minimongo-observable/meteor-observable.js

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,31 +10,36 @@ var MeteorObservable = (function () {
1010
for (var _i = 1; _i < arguments.length; _i++) {
1111
args[_i - 1] = arguments[_i];
1212
}
13+
var currentZone = Zone.current;
1314
var argumentsArray = Array.prototype.slice.call(arguments);
1415
var lastParam = argumentsArray[argumentsArray.length - 1];
1516
if (lastParam && _.isFunction(lastParam)) {
1617
throw new Error("Invalid MeteorObservable.call arguments:\n Your last param can't be a callback function, \n please remove it and use \".subscribe\" of the Observable!");
1718
}
18-
return rxjs_1.Observable.create(function (observer) {
19+
var obs = rxjs_1.Observable.create(function (observer) {
1920
Meteor.call.apply(Meteor, argumentsArray.concat([
2021
function (error, result) {
2122
if (error) {
22-
observer.error(error);
23-
observer.complete();
23+
currentZone.run(function () {
24+
observer.error(error);
25+
observer.complete();
26+
});
2427
}
2528
else {
26-
observer.next(result);
27-
observer.complete();
29+
currentZone.run(function () { return observer.next(result); });
2830
}
2931
}
3032
]));
3133
});
34+
obs.publish();
35+
return obs;
3236
};
3337
MeteorObservable.subscribe = function (name) {
3438
var args = [];
3539
for (var _i = 1; _i < arguments.length; _i++) {
3640
args[_i - 1] = arguments[_i];
3741
}
42+
var currentZone = Zone.current;
3843
var argumentsArray = Array.prototype.slice.call(arguments);
3944
var lastParam = argumentsArray[argumentsArray.length - 1];
4045
if (lastParam && _.isObject(lastParam) && (lastParam.onReady || lastParam.onError)) {
@@ -44,11 +49,13 @@ var MeteorObservable = (function () {
4449
var handle = Meteor.subscribe.apply(Meteor, argumentsArray.concat([
4550
{
4651
onError: function (error) {
47-
observer.error(error);
48-
observer.complete();
52+
currentZone.run(function () {
53+
observer.error(error);
54+
observer.complete();
55+
});
4956
},
5057
onReady: function () {
51-
observer.next();
58+
currentZone.run(function () { return observer.next(); });
5259
}
5360
}
5461
]));

dist/minimongo-observable/to-observable.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
"use strict";
22
var observable_cursor_1 = require('./observable-cursor');
3+
var _ = require('lodash');
4+
var COLLECTION_EVENTS_DEBOUNCE_TIMEFRAME = 16;
35
function toObservable(cursor) {
6+
var currentZone = Zone.current;
47
var observable = observable_cursor_1.ObservableCursor.create(function (observer) {
5-
var handleChange = function () {
6-
observer.next(cursor.fetch());
7-
};
8+
var rawHandleChange = function () { return currentZone.run(function () { return observer.next(cursor.fetch()); }); };
9+
var handleChange = _.debounce(rawHandleChange, COLLECTION_EVENTS_DEBOUNCE_TIMEFRAME);
810
var handler;
911
var isReactive = observable.isReactive();
1012
observable._cursorRef = cursor;

modules/minimongo-observable/meteor-observable.ts

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import * as _ from 'lodash';
44

55
export class MeteorObservable {
66
public static call<T>(name: string, ...args: any[]): Observable<T> {
7+
const currentZone = Zone.current;
78
const argumentsArray: Array<any> = Array.prototype.slice.call(arguments);
89
const lastParam = argumentsArray[argumentsArray.length - 1];
910

@@ -14,22 +15,28 @@ export class MeteorObservable {
1415
please remove it and use ".subscribe" of the Observable!`);
1516
}
1617

17-
return Observable.create((observer: Subscriber<Meteor.Error | T>) => {
18+
const obs = Observable.create((observer: Subscriber<Meteor.Error | T>) => {
1819
Meteor.call.apply(Meteor, argumentsArray.concat([
1920
(error: Meteor.Error, result: T) => {
2021
if (error) {
21-
observer.error(error);
22-
observer.complete();
22+
currentZone.run(() => {
23+
observer.error(error);
24+
observer.complete();
25+
});
2326
} else {
24-
observer.next(result);
25-
observer.complete();
27+
currentZone.run(() => observer.next(result));
2628
}
2729
}
2830
]));
2931
});
32+
33+
obs.publish();
34+
35+
return obs;
3036
}
3137

3238
public static subscribe<T>(name: string, ...args: any[]): ObservableMeteorSubscription<T> {
39+
const currentZone = Zone.current;
3340
const argumentsArray: Array<any> = Array.prototype.slice.call(arguments);
3441
const lastParam = argumentsArray[argumentsArray.length - 1];
3542

@@ -45,11 +52,13 @@ export class MeteorObservable {
4552
let handle = Meteor.subscribe.apply(Meteor, argumentsArray.concat([
4653
{
4754
onError: (error: Meteor.Error) => {
48-
observer.error(error);
49-
observer.complete();
55+
currentZone.run(() => {
56+
observer.error(error);
57+
observer.complete();
58+
});
5059
},
5160
onReady: () => {
52-
observer.next();
61+
currentZone.run(() => observer.next());
5362
}
5463
}
5564
]));

modules/minimongo-observable/to-observable.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
import {Subscriber} from 'rxjs/Rx';
22
import {ObservableCursor} from './observable-cursor';
3+
import * as _ from 'lodash';
4+
5+
const COLLECTION_EVENTS_DEBOUNCE_TIMEFRAME = 16;
36

47
export function toObservable<T>(cursor : Mongo.Cursor<T>) : ObservableCursor<Array<T>> {
8+
const currentZone = Zone.current;
59
const observable =
610
ObservableCursor.create((observer : Subscriber<Array<T>>) => {
7-
const handleChange = () => {
8-
observer.next(cursor.fetch());
9-
};
11+
const rawHandleChange = () => currentZone.run(() => observer.next(cursor.fetch()));
12+
const handleChange = _.debounce(
13+
rawHandleChange,
14+
COLLECTION_EVENTS_DEBOUNCE_TIMEFRAME);
1015

1116
let handler;
1217
let isReactive = observable.isReactive();

tests/client/unit/meteor-observable.spec.ts

Lines changed: 32 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,47 @@
11
import {chai} from 'meteor/practicalmeteor:chai';
22
import {sinon} from 'meteor/practicalmeteor:sinon';
3-
import {MeteorObservable, ObservableMeteorSubscription} from "angular2-meteor";
4-
import {Observable} from "rxjs";
3+
import {MeteorObservable, ObservableMeteorSubscription} from 'angular2-meteor';
4+
import {Observable} from 'rxjs';
55

66
const expect = chai.expect;
77

88
describe('MeteorObservable', function () {
9-
describe("call", function() {
9+
describe('call', function() {
1010

11-
it("Should return RxJS Observable when using 'call'", function() {
12-
let returnValue = MeteorObservable.call("testMethod");
11+
it('Should return RxJS Observable when using "call"', function() {
12+
let returnValue = MeteorObservable.call('testMethod');
1313
expect(returnValue instanceof Observable).to.equal(true);
1414
});
1515

16-
it("Should NOT run the actual 'call' method without subscribing to the result", function() {
17-
let spy = sinon.spy(Meteor, "call");
18-
MeteorObservable.call("testMethod");
16+
it('Should NOT run the actual "call" method without subscribing to the result', function() {
17+
let spy = sinon.spy(Meteor, 'call');
18+
MeteorObservable.call('testMethod');
1919
expect(spy.called).to.equal(false);
2020
spy.restore();
2121
});
2222

23-
it("Should run the actual 'call' method when subscribing to the result", function() {
24-
let spy = sinon.spy(Meteor, "call");
25-
let subscriptionHandler = MeteorObservable.call("testMethod").subscribe(function() {});
23+
it('Should run the actual "call" method when subscribing to the result', function() {
24+
let spy = sinon.spy(Meteor, 'call');
25+
let subscriptionHandler = MeteorObservable.call('testMethod').subscribe(function() {});
2626
expect(spy.calledOnce).to.equal(true);
2727
spy.restore();
2828
subscriptionHandler.unsubscribe();
2929
});
3030

31-
it("Should trigger the RxJS Observable 'next' callback when got the server response", function(done) {
31+
it('Should trigger the RxJS Observable "next" callback when got the server response', function(done) {
3232
let spy = sinon.spy();
33-
let subscriptionHandler = MeteorObservable.call("testMethod").subscribe((serverResponse) => {
33+
let subscriptionHandler = MeteorObservable.call('testMethod').subscribe((serverResponse) => {
3434
spy();
3535
expect(spy.callCount).to.equal(1);
36-
expect(serverResponse).to.equal("TEST_VALUE");
36+
expect(serverResponse).to.equal('TEST_VALUE');
3737
subscriptionHandler.unsubscribe();
3838
done();
3939
});
4040
});
4141

42-
it("Should trigger the RxJS Observable 'complete' callback when got the server response", function(done) {
42+
it('Should trigger the RxJS Observable "error" callback when got the server error', function(done) {
4343
let spy = sinon.spy();
44-
let subscriptionHandler = MeteorObservable.call("testMethod").subscribe(function() {}, function() {}, () => {
45-
spy();
46-
expect(spy.callCount).to.equal(1);
47-
subscriptionHandler.unsubscribe();
48-
done();
49-
});
50-
});
51-
52-
it("Should trigger the RxJS Observable 'error' callback when got the server error", function(done) {
53-
let spy = sinon.spy();
54-
let subscriptionHandler = MeteorObservable.call("NON_EXISTING_METHOD").subscribe(function() {}, (e) => {
44+
let subscriptionHandler = MeteorObservable.call('NON_EXISTING_METHOD').subscribe(function() {}, (e) => {
5545
spy();
5646
expect(spy.callCount).to.equal(1);
5747
expect(e instanceof Meteor.Error).to.equal(true);
@@ -61,46 +51,46 @@ describe('MeteorObservable', function () {
6151
});
6252
});
6353

64-
describe("subscribe", function() {
65-
it("Should return RxJS Observable when using 'subscribe'", function() {
66-
let returnValue = MeteorObservable.subscribe("test");
54+
describe('subscribe', function() {
55+
it('Should return RxJS Observable when using "subscribe"', function() {
56+
let returnValue = MeteorObservable.subscribe('test');
6757
expect(returnValue instanceof Observable).to.equal(true);
6858
});
6959

70-
it("Should NOT run the actual 'subscribe' method without subscribing to the result", function() {
71-
let spy = sinon.spy(Meteor, "subscribe");
72-
MeteorObservable.subscribe("test");
60+
it('Should NOT run the actual "subscribe" method without subscribing to the result', function() {
61+
let spy = sinon.spy(Meteor, 'subscribe');
62+
MeteorObservable.subscribe('test');
7363
expect(spy.called).to.equal(false);
7464
spy.restore();
7565
});
7666

77-
it("Should run the actual 'subscribe' method when subscribing to the result", function() {
78-
let spy = sinon.spy(Meteor, "subscribe");
79-
let subscriptionHandler = MeteorObservable.subscribe("test").subscribe(function() {});
67+
it('Should run the actual "subscribe" method when subscribing to the result', function() {
68+
let spy = sinon.spy(Meteor, 'subscribe');
69+
let subscriptionHandler = MeteorObservable.subscribe('test').subscribe(function() {});
8070
expect(spy.called).to.equal(true);
8171
spy.restore();
8272
subscriptionHandler.unsubscribe();
8373
});
8474

85-
it("Should call RxJS Observable 'next' callback when subscription is ready", function(done) {
75+
it('Should call RxJS Observable "next" callback when subscription is ready', function(done) {
8676
let spy = sinon.spy();
8777

88-
let subscriptionHandler = MeteorObservable.subscribe("test").subscribe(() => {
78+
let subscriptionHandler = MeteorObservable.subscribe('test').subscribe(() => {
8979
spy();
9080
expect(spy.callCount).to.equal(1);
9181
subscriptionHandler.unsubscribe();
9282
done();
9383
});
9484
});
9585

96-
it("Should stop the Meteor subscription when unsubscribing to the RxJS Observable", function(done) {
86+
it('Should stop the Meteor subscription when unsubscribing to the RxJS Observable', function(done) {
9787
function getSubscriptionsCount() {
9888
return Object.keys((<any>Meteor).default_connection._subscriptions).length;
9989
}
10090

10191
let baseSubscriptionsCount = getSubscriptionsCount();
10292

103-
let subscriptionHandler = MeteorObservable.subscribe("test").subscribe(() => {
93+
let subscriptionHandler = MeteorObservable.subscribe('test').subscribe(() => {
10494
expect(getSubscriptionsCount()).to.equal(baseSubscriptionsCount + 1);
10595
subscriptionHandler.unsubscribe();
10696
expect(getSubscriptionsCount()).to.equal(baseSubscriptionsCount);
@@ -109,15 +99,15 @@ describe('MeteorObservable', function () {
10999
});
110100

111101

112-
it("Should stop the Meteor subscription when calling stop of the Observable", function(done) {
102+
it('Should stop the Meteor subscription when calling stop of the Observable', function(done) {
113103
function getSubscriptionsCount() {
114104
return Object.keys((<any>Meteor).default_connection._subscriptions).length;
115105
}
116106

117107
let baseSubscriptionsCount = getSubscriptionsCount();
118108

119-
let obs : ObservableMeteorSubscription<any> = MeteorObservable.subscribe("test");
120-
let subscriptionHandler = obs.subscribe(() => {
109+
let obs : ObservableMeteorSubscription<any> = MeteorObservable.subscribe('test');
110+
obs.subscribe(() => {
121111
expect(getSubscriptionsCount()).to.equal(baseSubscriptionsCount + 1);
122112
obs.stop();
123113
expect(getSubscriptionsCount()).to.equal(baseSubscriptionsCount);

0 commit comments

Comments
 (0)