Skip to content

Commit 859ec10

Browse files
committed
initial
1 parent bbc52b2 commit 859ec10

File tree

3 files changed

+33
-28
lines changed

3 files changed

+33
-28
lines changed

item.js

+14-18
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
1+
// signal / effect
22
const relatedEffects = new WeakMap();
33
let currentEffect = null;
44

@@ -7,18 +7,16 @@ export function effect(fn){
77
currentEffect = fn;
88
if (outer) {
99
(outer.nested ??= new Set()).add(fn);
10+
if (fn.parent && fn.parent !== outer) throw('effect(cb) callbacks should not be reused for other effects');
1011
fn.parent = outer;
1112
}
1213
fn();
1314
currentEffect = outer;
1415
return () => fn.disposed = true
1516
}
16-
17-
1817
let batches = null;
1918
function batch(effect) {
2019
if (batches) return batches.add(effect);
21-
2220
batches = new Set([effect]);
2321
Promise.resolve().then(()=>{ // setImmediate-alternative
2422
batches.forEach(fn => {
@@ -29,23 +27,21 @@ function batch(effect) {
2927
batches = null; // restart batch
3028
});
3129
}
32-
33-
34-
export function signalize(item) {
35-
item.addEventListener('getIn', ({detail:{item}}) => {
36-
if (!currentEffect) return;
37-
if (!relatedEffects.has(item)) relatedEffects.set(item, new Set());
38-
relatedEffects.get(item).add(currentEffect);
39-
});
40-
item.addEventListener('changeIn', ({detail:{item}}) => {
41-
const effects = relatedEffects.get(item);
42-
if (!effects) return;
30+
function registerCurrentEffectFor(signal) {
31+
if (currentEffect) {
32+
if (!relatedEffects.has(signal)) relatedEffects.set(signal, new Set());
33+
relatedEffects.get(signal).add(currentEffect);
34+
}
35+
}
36+
function triggerEffectsFor(signal) {
37+
const effects = relatedEffects.get(signal);
38+
if (effects) { // "&& effects.size" faster?
4339
effects.forEach(fn => {
4440
fn.nested?.forEach(fn => fn.disposed = true); // dispose child-effects
4541
if (fn.disposed) return effects.delete(fn);
4642
batch(fn);
4743
});
48-
});
44+
}
4945
}
5046

5147

@@ -62,6 +58,7 @@ export class Item extends EventTarget {
6258
super();
6359
this.#parent = parent;
6460
this.#key = key;
61+
this.addEventListener('change', () => triggerEffectsFor(this) );
6562
}
6663

6764
get key(){ return this.#key }
@@ -72,8 +69,8 @@ export class Item extends EventTarget {
7269
if (this.#isgetting) throw new Error('circular get');
7370
this.#isgetting = true;
7471
dispatchEvent(this, 'get', { item: this, value:this.#value });
72+
registerCurrentEffectFor(this);
7573
this.#isgetting = false;
76-
//if (!this.#filled) throw new Error('value was never set');
7774
return this.$get();
7875
}
7976
set value(value){
@@ -90,7 +87,6 @@ export class Item extends EventTarget {
9087
} else {
9188
const value = this.#value ??= Object.create(null); // if undefined, create object (todo? should always be object)
9289
return Object.fromEntries(Object.entries(value).map(([key, {value}]) => [key, value]));
93-
//return Object.fromEntries(Object.entries(this.#value).map(([key, {value}]) => [key, value]));
9490
}
9591
}
9692
$set(value){

tests/signalize.html tests/effect.html

+17-6
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,26 @@ <h1>Test</h1>
1313

1414
// local storage
1515

16-
import {item, effect, signalize } from "../item.js";
16+
import {item, effect} from "../item.js";
1717

18-
const itm = item({outer:'0', inner:'0'});
19-
signalize(itm);
18+
const itm = item({outer:'0', inner:'0', deeper:0});
2019

20+
const eff = ()=>{
21+
22+
log("inner effect, value:" + itm.item('inner').value);
23+
24+
}
2125

2226
effect(()=>{
2327

2428
log("outer effect, value:" + itm.item('outer').value);
2529

2630
effect(()=>{
2731

32+
effect(()=>{
33+
log("deeper effect (bevore inner), value:" + itm.item('deeper').value);
34+
});
35+
2836
log("inner effect, value:" + itm.item('inner').value);
2937

3038
});
@@ -36,28 +44,31 @@ <h1>Test</h1>
3644
console.log(msg)
3745
}
3846

39-
log('<br>start mutating<br>');
47+
log('<br>start mutating (firstly skiped because batched)<br>');
4048

4149
itm.item('inner').value = '2';
4250
itm.item('outer').value = '2';
51+
itm.item('deeper').value = 2;
4352

44-
log("<br>new values (skiped because batched)<br>");
53+
log("<br>new values<br>");
4554

4655
itm.item('inner').value = '3';
4756
itm.item('outer').value = '3';
57+
itm.item('deeper').value = 3;
4858

49-
log("<br>new values<br>");
5059

5160
setTimeout(()=>{
5261
log("<br>new values after 50ms<br>");
5362
itm.item('inner').value = '4';
5463
itm.item('outer').value = '4';
64+
itm.item('deeper').value = 4;
5565
}, 50);
5666

5767
setTimeout(()=>{
5868
log("<br>new values after 100ms<br>");
5969
itm.item('inner').value = '5';
6070
itm.item('outer').value = '5';
71+
itm.item('deeper').value = 5;
6172
}, 100);
6273

6374
</script>

tests/signalizeLocalStorage.html tests/effectAndLocalStorage.html

+2-4
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,10 @@ <h1>Test</h1>
1010

1111
<script type=module>
1212

13-
import {effect, signalize, proxy} from "../item.js";
13+
import {effect, proxy} from "../item.js";
1414
import {localStorageItem} from "../drivers/localStorage.js";
1515

16-
let item = localStorageItem();
17-
signalize(item);
18-
window.ls = proxy(item);
16+
window.ls = proxy(localStorageItem());
1917

2018
effect(()=>{
2119
sayHi.innerHTML = 'Hi '+ls.firstname+' '+ls.lastname+'!';

0 commit comments

Comments
 (0)