Skip to content

Commit 6a76d5c

Browse files
Merge pull request #14 from efflore/bugfix/v0.8.2
slightly optimized scheduler
2 parents fd2a81f + 0f1fd94 commit 6a76d5c

12 files changed

+81
-72
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
UIElement - the "look ma, no JS framework!" library bringing signals-based reactivity to vanilla Web Components
44

5-
Version 0.8.1
5+
Version 0.8.2
66

77
## What is UIElement?
88

cause-effect.js

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -33,24 +33,6 @@ const scheduler = () => {
3333
const effectQueue = new Map();
3434
const cleanupQueue = new Map();
3535
let requestId;
36-
const requestTick = () => {
37-
if (requestId)
38-
cancelAnimationFrame(requestId);
39-
requestId = requestAnimationFrame(flush);
40-
};
41-
const enqueue = (element, prop, fn) => {
42-
if (!effectQueue.has(element))
43-
effectQueue.set(element, new Map());
44-
const elEffects = effectQueue.get(element);
45-
if (!elEffects.has(prop))
46-
elEffects.set(prop, fn);
47-
requestTick();
48-
};
49-
const cleanup = (effect, fn) => {
50-
if (!cleanupQueue.has(effect))
51-
cleanupQueue.set(effect, fn);
52-
requestTick();
53-
};
5436
const run = (fn, msg) => {
5537
try {
5638
fn();
@@ -70,8 +52,27 @@ const scheduler = () => {
7052
run(fn, 'Cleanup failed');
7153
cleanupQueue.clear();
7254
};
55+
const requestTick = () => {
56+
if (requestId)
57+
cancelAnimationFrame(requestId);
58+
requestId = requestAnimationFrame(flush);
59+
};
60+
const getEffectMap = (key) => {
61+
if (!effectQueue.has(key))
62+
effectQueue.set(key, new Map());
63+
return effectQueue.get(key);
64+
};
65+
const addToQueue = (map) => (key, fn) => {
66+
const more = !map.has(key);
67+
map.set(key, fn);
68+
if (more)
69+
requestTick();
70+
};
7371
queueMicrotask(flush); // initial flush when the call stack is empty
74-
return { enqueue, cleanup };
72+
return {
73+
enqueue: (element, prop, fn) => addToQueue(getEffectMap(element))(prop, fn),
74+
cleanup: addToQueue(cleanupQueue)
75+
};
7576
};
7677

7778
/* === Internal === */
@@ -174,8 +175,7 @@ const effect = (fn) => {
174175
activeEffect = n;
175176
const cleanupFn = fn((element, prop, callback) => {
176177
enqueue(element, prop, callback);
177-
if (!targets.has(element))
178-
targets.add(element);
178+
targets.add(element);
179179
});
180180
if (isFunction(cleanupFn))
181181
cleanup(n, cleanupFn);

cause-effect.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

index.js

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -94,24 +94,6 @@ const scheduler = () => {
9494
const effectQueue = new Map();
9595
const cleanupQueue = new Map();
9696
let requestId;
97-
const requestTick = () => {
98-
if (requestId)
99-
cancelAnimationFrame(requestId);
100-
requestId = requestAnimationFrame(flush);
101-
};
102-
const enqueue = (element, prop, fn) => {
103-
if (!effectQueue.has(element))
104-
effectQueue.set(element, new Map());
105-
const elEffects = effectQueue.get(element);
106-
if (!elEffects.has(prop))
107-
elEffects.set(prop, fn);
108-
requestTick();
109-
};
110-
const cleanup = (effect, fn) => {
111-
if (!cleanupQueue.has(effect))
112-
cleanupQueue.set(effect, fn);
113-
requestTick();
114-
};
11597
const run = (fn, msg) => {
11698
try {
11799
fn();
@@ -131,8 +113,27 @@ const scheduler = () => {
131113
run(fn, 'Cleanup failed');
132114
cleanupQueue.clear();
133115
};
116+
const requestTick = () => {
117+
if (requestId)
118+
cancelAnimationFrame(requestId);
119+
requestId = requestAnimationFrame(flush);
120+
};
121+
const getEffectMap = (key) => {
122+
if (!effectQueue.has(key))
123+
effectQueue.set(key, new Map());
124+
return effectQueue.get(key);
125+
};
126+
const addToQueue = (map) => (key, fn) => {
127+
const more = !map.has(key);
128+
map.set(key, fn);
129+
if (more)
130+
requestTick();
131+
};
134132
queueMicrotask(flush); // initial flush when the call stack is empty
135-
return { enqueue, cleanup };
133+
return {
134+
enqueue: (element, prop, fn) => addToQueue(getEffectMap(element))(prop, fn),
135+
cleanup: addToQueue(cleanupQueue)
136+
};
136137
};
137138

138139
/* === Internal === */
@@ -204,8 +205,7 @@ const effect = (fn) => {
204205
activeEffect = n;
205206
const cleanupFn = fn((element, prop, callback) => {
206207
enqueue(element, prop, callback);
207-
if (!targets.has(element))
208-
targets.add(element);
208+
targets.add(element);
209209
});
210210
if (isFunction(cleanupFn))
211211
cleanup(n, cleanupFn);

index.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { setAttribute, setProperty, setStyle, setText, toggleAttribute, toggleCl
99

1010
/**
1111
* @name UIElement
12-
* @version 0.8.1
12+
* @version 0.8.2
1313
*/
1414

1515
export {

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@efflore/ui-element",
3-
"version": "0.8.1",
3+
"version": "0.8.2",
44
"description": "UIElement - minimal reactive framework based on Web Components",
55
"main": "index.min.js",
66
"types": "types/ui-element.d.ts",

src/cause-effect.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ const effect = (fn: EffectCallback) => {
139139
activeEffect = n
140140
const cleanupFn = fn((element: Element, prop: string, callback: (element: Element) => () => void): void => {
141141
enqueue(element, prop, callback)
142-
if (!targets.has(element)) targets.add(element)
142+
targets.add(element)
143143
})
144144
if (isFunction(cleanupFn)) cleanup(n, cleanupFn)
145145
activeEffect = prev

src/core/scheduler.ts

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,17 @@
1-
import type { Effect } from '../cause-effect';
21
import { log, LOG_ERROR } from './log';
32

3+
/* === Types === */
4+
5+
type UnknownFunction = (...args: unknown[]) => unknown
6+
type ElementFunction = (element: Element) => () => void
7+
48
/* === Exported Function === */
59

610
const scheduler = () => {
711
const effectQueue = new Map()
812
const cleanupQueue = new Map()
913
let requestId: number
1014

11-
const requestTick = () => {
12-
if (requestId) cancelAnimationFrame(requestId)
13-
requestId = requestAnimationFrame(flush)
14-
}
15-
16-
const enqueue = (element: Element, prop: string, fn: (element: Element) => () => void) => {
17-
if (!effectQueue.has(element)) effectQueue.set(element, new Map())
18-
const elEffects = effectQueue.get(element)
19-
if (!elEffects.has(prop)) elEffects.set(prop, fn)
20-
requestTick()
21-
}
22-
23-
const cleanup = (effect: Effect, fn: () => void) => {
24-
if (!cleanupQueue.has(effect)) cleanupQueue.set(effect, fn)
25-
requestTick()
26-
}
27-
2815
const run = (fn: () => void, msg: string) => {
2916
try {
3017
fn()
@@ -44,9 +31,30 @@ const scheduler = () => {
4431
run(fn, 'Cleanup failed')
4532
cleanupQueue.clear()
4633
}
34+
35+
const requestTick = () => {
36+
if (requestId) cancelAnimationFrame(requestId)
37+
requestId = requestAnimationFrame(flush)
38+
}
39+
40+
const getEffectMap = (key: Element) => {
41+
if (!effectQueue.has(key)) effectQueue.set(key, new Map())
42+
return effectQueue.get(key)
43+
}
44+
45+
const addToQueue = (map: Map<unknown, UnknownFunction>) =>
46+
(key: unknown, fn: UnknownFunction) => {
47+
const more = !map.has(key)
48+
map.set(key, fn)
49+
if (more) requestTick()
50+
}
51+
4752
queueMicrotask(flush) // initial flush when the call stack is empty
53+
return {
54+
enqueue: (element: Element, prop: string, fn: ElementFunction) => addToQueue(getEffectMap(element))(prop, fn),
55+
cleanup: addToQueue(cleanupQueue)
56+
}
4857

49-
return { enqueue, cleanup }
5058
}
5159

5260
export default scheduler

src/ui-element.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { setText, setProperty, setAttribute, toggleAttribute, toggleClass, setSt
1111

1212
/* === Types === */
1313

14-
type AttributeParser = (<T>(value: string[], element: UIElement, old: string | undefined) => T[])
14+
type AttributeParser = (value: string[], element: UIElement, old: string | undefined) => unknown[]
1515

1616
type AttributeMap = Record<string, AttributeParser>
1717

types/core/scheduler.d.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import type { Effect } from '../cause-effect';
1+
type UnknownFunction = (...args: unknown[]) => unknown;
2+
type ElementFunction = (element: Element) => () => void;
23
declare const scheduler: () => {
3-
enqueue: (element: Element, prop: string, fn: (element: Element) => () => void) => void;
4-
cleanup: (effect: Effect, fn: () => void) => void;
4+
enqueue: (element: Element, prop: string, fn: ElementFunction) => void;
5+
cleanup: (key: unknown, fn: UnknownFunction) => void;
56
};
67
export default scheduler;

types/ui-element.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { type StateMap, pass } from './lib/pass';
77
import { on, off, dispatch } from './lib/event';
88
import { asBoolean, asInteger, asJSON, asNumber, asString } from './lib/parse-attribute';
99
import { setText, setProperty, setAttribute, toggleAttribute, toggleClass, setStyle } from './lib/auto-effects';
10-
type AttributeParser = (<T>(value: string[], element: UIElement, old: string | undefined) => T[]);
10+
type AttributeParser = (value: string[], element: UIElement, old: string | undefined) => unknown[];
1111
type AttributeMap = Record<string, AttributeParser>;
1212
/**
1313
* Base class for reactive custom elements

0 commit comments

Comments
 (0)