Skip to content

Commit

Permalink
Merge pull request #14 from efflore/bugfix/v0.8.2
Browse files Browse the repository at this point in the history
slightly optimized scheduler
  • Loading branch information
estherbrunner authored Aug 30, 2024
2 parents fd2a81f + 0f1fd94 commit 6a76d5c
Show file tree
Hide file tree
Showing 12 changed files with 81 additions and 72 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

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

Version 0.8.1
Version 0.8.2

## What is UIElement?

Expand Down
42 changes: 21 additions & 21 deletions cause-effect.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,24 +33,6 @@ const scheduler = () => {
const effectQueue = new Map();
const cleanupQueue = new Map();
let requestId;
const requestTick = () => {
if (requestId)
cancelAnimationFrame(requestId);
requestId = requestAnimationFrame(flush);
};
const enqueue = (element, prop, fn) => {
if (!effectQueue.has(element))
effectQueue.set(element, new Map());
const elEffects = effectQueue.get(element);
if (!elEffects.has(prop))
elEffects.set(prop, fn);
requestTick();
};
const cleanup = (effect, fn) => {
if (!cleanupQueue.has(effect))
cleanupQueue.set(effect, fn);
requestTick();
};
const run = (fn, msg) => {
try {
fn();
Expand All @@ -70,8 +52,27 @@ const scheduler = () => {
run(fn, 'Cleanup failed');
cleanupQueue.clear();
};
const requestTick = () => {
if (requestId)
cancelAnimationFrame(requestId);
requestId = requestAnimationFrame(flush);
};
const getEffectMap = (key) => {
if (!effectQueue.has(key))
effectQueue.set(key, new Map());
return effectQueue.get(key);
};
const addToQueue = (map) => (key, fn) => {
const more = !map.has(key);
map.set(key, fn);
if (more)
requestTick();
};
queueMicrotask(flush); // initial flush when the call stack is empty
return { enqueue, cleanup };
return {
enqueue: (element, prop, fn) => addToQueue(getEffectMap(element))(prop, fn),
cleanup: addToQueue(cleanupQueue)
};
};

/* === Internal === */
Expand Down Expand Up @@ -174,8 +175,7 @@ const effect = (fn) => {
activeEffect = n;
const cleanupFn = fn((element, prop, callback) => {
enqueue(element, prop, callback);
if (!targets.has(element))
targets.add(element);
targets.add(element);
});
if (isFunction(cleanupFn))
cleanup(n, cleanupFn);
Expand Down
2 changes: 1 addition & 1 deletion cause-effect.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

42 changes: 21 additions & 21 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,24 +94,6 @@ const scheduler = () => {
const effectQueue = new Map();
const cleanupQueue = new Map();
let requestId;
const requestTick = () => {
if (requestId)
cancelAnimationFrame(requestId);
requestId = requestAnimationFrame(flush);
};
const enqueue = (element, prop, fn) => {
if (!effectQueue.has(element))
effectQueue.set(element, new Map());
const elEffects = effectQueue.get(element);
if (!elEffects.has(prop))
elEffects.set(prop, fn);
requestTick();
};
const cleanup = (effect, fn) => {
if (!cleanupQueue.has(effect))
cleanupQueue.set(effect, fn);
requestTick();
};
const run = (fn, msg) => {
try {
fn();
Expand All @@ -131,8 +113,27 @@ const scheduler = () => {
run(fn, 'Cleanup failed');
cleanupQueue.clear();
};
const requestTick = () => {
if (requestId)
cancelAnimationFrame(requestId);
requestId = requestAnimationFrame(flush);
};
const getEffectMap = (key) => {
if (!effectQueue.has(key))
effectQueue.set(key, new Map());
return effectQueue.get(key);
};
const addToQueue = (map) => (key, fn) => {
const more = !map.has(key);
map.set(key, fn);
if (more)
requestTick();
};
queueMicrotask(flush); // initial flush when the call stack is empty
return { enqueue, cleanup };
return {
enqueue: (element, prop, fn) => addToQueue(getEffectMap(element))(prop, fn),
cleanup: addToQueue(cleanupQueue)
};
};

/* === Internal === */
Expand Down Expand Up @@ -204,8 +205,7 @@ const effect = (fn) => {
activeEffect = n;
const cleanupFn = fn((element, prop, callback) => {
enqueue(element, prop, callback);
if (!targets.has(element))
targets.add(element);
targets.add(element);
});
if (isFunction(cleanupFn))
cleanup(n, cleanupFn);
Expand Down
2 changes: 1 addition & 1 deletion index.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { setAttribute, setProperty, setStyle, setText, toggleAttribute, toggleCl

/**
* @name UIElement
* @version 0.8.1
* @version 0.8.2
*/

export {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@efflore/ui-element",
"version": "0.8.1",
"version": "0.8.2",
"description": "UIElement - minimal reactive framework based on Web Components",
"main": "index.min.js",
"types": "types/ui-element.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion src/cause-effect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ const effect = (fn: EffectCallback) => {
activeEffect = n
const cleanupFn = fn((element: Element, prop: string, callback: (element: Element) => () => void): void => {
enqueue(element, prop, callback)
if (!targets.has(element)) targets.add(element)
targets.add(element)
})
if (isFunction(cleanupFn)) cleanup(n, cleanupFn)
activeEffect = prev
Expand Down
46 changes: 27 additions & 19 deletions src/core/scheduler.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,17 @@
import type { Effect } from '../cause-effect';
import { log, LOG_ERROR } from './log';

/* === Types === */

type UnknownFunction = (...args: unknown[]) => unknown
type ElementFunction = (element: Element) => () => void

/* === Exported Function === */

const scheduler = () => {
const effectQueue = new Map()
const cleanupQueue = new Map()
let requestId: number

const requestTick = () => {
if (requestId) cancelAnimationFrame(requestId)
requestId = requestAnimationFrame(flush)
}

const enqueue = (element: Element, prop: string, fn: (element: Element) => () => void) => {
if (!effectQueue.has(element)) effectQueue.set(element, new Map())
const elEffects = effectQueue.get(element)
if (!elEffects.has(prop)) elEffects.set(prop, fn)
requestTick()
}

const cleanup = (effect: Effect, fn: () => void) => {
if (!cleanupQueue.has(effect)) cleanupQueue.set(effect, fn)
requestTick()
}

const run = (fn: () => void, msg: string) => {
try {
fn()
Expand All @@ -44,9 +31,30 @@ const scheduler = () => {
run(fn, 'Cleanup failed')
cleanupQueue.clear()
}

const requestTick = () => {
if (requestId) cancelAnimationFrame(requestId)
requestId = requestAnimationFrame(flush)
}

const getEffectMap = (key: Element) => {
if (!effectQueue.has(key)) effectQueue.set(key, new Map())
return effectQueue.get(key)
}

const addToQueue = (map: Map<unknown, UnknownFunction>) =>
(key: unknown, fn: UnknownFunction) => {
const more = !map.has(key)
map.set(key, fn)
if (more) requestTick()
}

queueMicrotask(flush) // initial flush when the call stack is empty
return {
enqueue: (element: Element, prop: string, fn: ElementFunction) => addToQueue(getEffectMap(element))(prop, fn),
cleanup: addToQueue(cleanupQueue)
}

return { enqueue, cleanup }
}

export default scheduler
2 changes: 1 addition & 1 deletion src/ui-element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { setText, setProperty, setAttribute, toggleAttribute, toggleClass, setSt

/* === Types === */

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

type AttributeMap = Record<string, AttributeParser>

Expand Down
7 changes: 4 additions & 3 deletions types/core/scheduler.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Effect } from '../cause-effect';
type UnknownFunction = (...args: unknown[]) => unknown;
type ElementFunction = (element: Element) => () => void;
declare const scheduler: () => {
enqueue: (element: Element, prop: string, fn: (element: Element) => () => void) => void;
cleanup: (effect: Effect, fn: () => void) => void;
enqueue: (element: Element, prop: string, fn: ElementFunction) => void;
cleanup: (key: unknown, fn: UnknownFunction) => void;
};
export default scheduler;
2 changes: 1 addition & 1 deletion types/ui-element.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { type StateMap, pass } from './lib/pass';
import { on, off, dispatch } from './lib/event';
import { asBoolean, asInteger, asJSON, asNumber, asString } from './lib/parse-attribute';
import { setText, setProperty, setAttribute, toggleAttribute, toggleClass, setStyle } from './lib/auto-effects';
type AttributeParser = (<T>(value: string[], element: UIElement, old: string | undefined) => T[]);
type AttributeParser = (value: string[], element: UIElement, old: string | undefined) => unknown[];
type AttributeMap = Record<string, AttributeParser>;
/**
* Base class for reactive custom elements
Expand Down

0 comments on commit 6a76d5c

Please sign in to comment.