Add empty-subcription detection to frptools
bump to v1.1.0
This commit is contained in:
parent
6ce9ab7079
commit
a26d268f8a
@ -40,10 +40,12 @@ inViewport(false);
|
|||||||
### Subscribe to changes
|
### Subscribe to changes
|
||||||
|
|
||||||
Call the `subscribe` method with a callback that will be called when the observable is changed to a
|
Call the `subscribe` method with a callback that will be called when the observable is changed to a
|
||||||
different value. The returned function can be called to unsubscribe from the observable.
|
different value. The returned function can be called to unsubscribe from the observable. When called
|
||||||
|
it will provide the count of remaining subscriptions.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const unsubscribe = inViewport.subscribe(console.log.bind(console));
|
const unsubscribe = inViewport.subscribe(console.log.bind(console));
|
||||||
|
const remainingSubscriptionCount = unsubscribe();
|
||||||
```
|
```
|
||||||
|
|
||||||
# [computed](./src/computed.js)
|
# [computed](./src/computed.js)
|
||||||
@ -81,10 +83,12 @@ Call it to receive the stored value, recomputing if necessary.
|
|||||||
### Subscribe to changes
|
### Subscribe to changes
|
||||||
|
|
||||||
Call the subscribe method with a callback that will be called when the computed result changes to a
|
Call the subscribe method with a callback that will be called when the computed result changes to a
|
||||||
different value. The returned function can be called to unsubscribe from the observable.
|
different value. The returned function can be called to unsubscribe from the observable. When called
|
||||||
|
it will provide the count of remaining subscriptions.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const unsubscribe = inViewport.subscribe(console.log.bind(console));
|
const unsubscribe = inViewport.subscribe(console.log.bind(console));
|
||||||
|
const remainingSubscriptionCount = unsubscribe();
|
||||||
```
|
```
|
||||||
|
|
||||||
**NOTE**: Subscribing to a computed forces it to recompute every time an upstream dependency
|
**NOTE**: Subscribing to a computed forces it to recompute every time an upstream dependency
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "frptools",
|
"name": "frptools",
|
||||||
"version": "1.0.0",
|
"version": "1.1.0",
|
||||||
"description": "Observable and Computed data streams",
|
"description": "Observable and Computed data streams",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"jsnext:main": "src/index.js",
|
"jsnext:main": "src/index.js",
|
||||||
|
|||||||
@ -40,17 +40,107 @@ describe('computed', () => {
|
|||||||
|
|
||||||
a(1);
|
a(1);
|
||||||
expect(runCount).toEqual(0);
|
expect(runCount).toEqual(0);
|
||||||
|
// b evaluates
|
||||||
expect(b()).toEqual(1);
|
expect(b()).toEqual(1);
|
||||||
expect(runCount).toEqual(1);
|
expect(runCount).toEqual(1);
|
||||||
|
// b does not evaluate
|
||||||
expect(b()).toEqual(1);
|
expect(b()).toEqual(1);
|
||||||
expect(runCount).toEqual(1);
|
expect(runCount).toEqual(1);
|
||||||
currentValue = 3;
|
currentValue = 3;
|
||||||
|
// b does not evaluate
|
||||||
a(3);
|
a(3);
|
||||||
expect(runCount).toEqual(1);
|
expect(runCount).toEqual(1);
|
||||||
|
// b evaluates
|
||||||
expect(b()).toEqual(9);
|
expect(b()).toEqual(9);
|
||||||
expect(runCount).toEqual(2);
|
expect(runCount).toEqual(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('computes automatically when subscribed', () => {
|
||||||
|
let runCount = 0;
|
||||||
|
let subRunCount = 0;
|
||||||
|
let currentValue = 1;
|
||||||
|
const a = observable(0);
|
||||||
|
const b = computed(
|
||||||
|
val => {
|
||||||
|
runCount += 1;
|
||||||
|
expect(val).toEqual(currentValue);
|
||||||
|
return val * val;
|
||||||
|
},
|
||||||
|
[a]
|
||||||
|
);
|
||||||
|
|
||||||
|
// b does not evaluate
|
||||||
|
a(1);
|
||||||
|
expect(runCount).toEqual(0);
|
||||||
|
// b evaluates
|
||||||
|
expect(b()).toEqual(1);
|
||||||
|
expect(runCount).toEqual(1);
|
||||||
|
// b does not evaluate
|
||||||
|
expect(b()).toEqual(1);
|
||||||
|
expect(runCount).toEqual(1);
|
||||||
|
|
||||||
|
const cancelSubscription = b.subscribe(val => {
|
||||||
|
subRunCount += 1;
|
||||||
|
expect(val).toEqual(currentValue * currentValue);
|
||||||
|
});
|
||||||
|
|
||||||
|
currentValue = 3;
|
||||||
|
// b evaluates
|
||||||
|
a(3);
|
||||||
|
expect(runCount).toEqual(2);
|
||||||
|
expect(subRunCount).toEqual(1);
|
||||||
|
// b does not evaluate
|
||||||
|
expect(b()).toEqual(9);
|
||||||
|
expect(runCount).toEqual(2);
|
||||||
|
expect(subRunCount).toEqual(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('honors cancelled subscriptions', () => {
|
||||||
|
let runCount = 0;
|
||||||
|
let subRunCount = 0;
|
||||||
|
let currentValue = 1;
|
||||||
|
const a = observable(0);
|
||||||
|
const b = computed(
|
||||||
|
val => {
|
||||||
|
runCount += 1;
|
||||||
|
expect(val).toEqual(currentValue);
|
||||||
|
return val * val;
|
||||||
|
},
|
||||||
|
[a]
|
||||||
|
);
|
||||||
|
const cancelSubscription = b.subscribe(val => {
|
||||||
|
subRunCount += 1;
|
||||||
|
expect(val).toEqual(currentValue * currentValue);
|
||||||
|
});
|
||||||
|
|
||||||
|
const cancelSubscription2 = b.subscribe(val => {
|
||||||
|
subRunCount += 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
// b evaluates
|
||||||
|
a(1);
|
||||||
|
expect(runCount).toEqual(1);
|
||||||
|
expect(subRunCount).toEqual(2);
|
||||||
|
// b does not evaluate
|
||||||
|
expect(b()).toEqual(1);
|
||||||
|
expect(runCount).toEqual(1);
|
||||||
|
expect(subRunCount).toEqual(2);
|
||||||
|
|
||||||
|
expect(cancelSubscription()).toEqual(1);
|
||||||
|
|
||||||
|
currentValue = 3;
|
||||||
|
// b evaluates
|
||||||
|
a(3);
|
||||||
|
expect(runCount).toEqual(2);
|
||||||
|
expect(subRunCount).toEqual(3);
|
||||||
|
// b does not evaluate
|
||||||
|
expect(b()).toEqual(9);
|
||||||
|
expect(runCount).toEqual(2);
|
||||||
|
expect(subRunCount).toEqual(3);
|
||||||
|
|
||||||
|
expect(cancelSubscription2()).toEqual(0);
|
||||||
|
});
|
||||||
|
|
||||||
it('can be detached', () => {
|
it('can be detached', () => {
|
||||||
const a = observable(2);
|
const a = observable(2);
|
||||||
const b = computed(square, [a]);
|
const b = computed(square, [a]);
|
||||||
|
|||||||
@ -44,12 +44,21 @@ describe('observable', () => {
|
|||||||
runCount += 1;
|
runCount += 1;
|
||||||
expect(val).toEqual(currentValue);
|
expect(val).toEqual(currentValue);
|
||||||
});
|
});
|
||||||
|
const cancelSubscription2 = a.subscribe(val => {
|
||||||
|
runCount += 1;
|
||||||
|
expect(val).toEqual(currentValue);
|
||||||
|
});
|
||||||
expect(a(1)).toEqual(1);
|
expect(a(1)).toEqual(1);
|
||||||
expect(runCount).toEqual(1);
|
expect(runCount).toEqual(2);
|
||||||
expect(a(1)).toEqual(1);
|
expect(a(1)).toEqual(1);
|
||||||
expect(runCount).toEqual(1);
|
expect(runCount).toEqual(2);
|
||||||
cancelSubscription();
|
expect(cancelSubscription()).toEqual(1);
|
||||||
|
currentValue = 3;
|
||||||
expect(a(3)).toEqual(3);
|
expect(a(3)).toEqual(3);
|
||||||
expect(runCount).toEqual(1);
|
expect(runCount).toEqual(3);
|
||||||
|
expect(cancelSubscription2()).toEqual(0);
|
||||||
|
currentValue = 4;
|
||||||
|
expect(a(4)).toEqual(4);
|
||||||
|
expect(runCount).toEqual(3);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -31,7 +31,10 @@ export function computed(fn, dependencies = []) {
|
|||||||
|
|
||||||
accessor.subscribe = fn => {
|
accessor.subscribe = fn => {
|
||||||
subscribers.add(fn);
|
subscribers.add(fn);
|
||||||
return () => subscribers.delete(fn);
|
return () => {
|
||||||
|
subscribers.delete(fn);
|
||||||
|
return subscribers.size;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
accessor._d = fn => {
|
accessor._d = fn => {
|
||||||
|
|||||||
@ -11,7 +11,10 @@ export function observable(store) {
|
|||||||
|
|
||||||
accessor.subscribe = accessor._d = fn => {
|
accessor.subscribe = accessor._d = fn => {
|
||||||
subscribers.add(fn);
|
subscribers.add(fn);
|
||||||
return () => subscribers.delete(fn);
|
return () => {
|
||||||
|
subscribers.delete(fn);
|
||||||
|
return subscribers.size;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
accessor.unsubscribeAll = () => subscribers.clear();
|
accessor.unsubscribeAll = () => subscribers.clear();
|
||||||
|
|||||||
Reference in New Issue
Block a user