Skip to content

Commit

Permalink
refactor: optimize event delegation logic
Browse files Browse the repository at this point in the history
  • Loading branch information
DylanPiercey committed Jan 16, 2024
1 parent adb0b75 commit 5ec47eb
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 69 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ jobs:
cache: npm
- name: Install dependencies
run: npm ci
- name: Build packages
run: npm run build
- name: Run tests
run: npm run ci:test
- name: Report code coverage
Expand Down
70 changes: 35 additions & 35 deletions .sizes.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,81 +7,81 @@
{
"name": "*",
"total": {
"min": 13292,
"gzip": 5721,
"brotli": 5182
"min": 13224,
"gzip": 5694,
"brotli": 5180
}
},
{
"name": "counter",
"user": {
"min": 351,
"gzip": 278,
"brotli": 268
"gzip": 279,
"brotli": 242
},
"runtime": {
"min": 4031,
"gzip": 1883,
"brotli": 1688
"min": 3965,
"gzip": 1862,
"brotli": 1667
},
"total": {
"min": 4382,
"gzip": 2161,
"brotli": 1956
"min": 4316,
"gzip": 2141,
"brotli": 1909
}
},
{
"name": "counter 💧",
"user": {
"min": 204,
"gzip": 183,
"brotli": 154
"gzip": 180,
"brotli": 153
},
"runtime": {
"min": 2593,
"gzip": 1350,
"brotli": 1215
"min": 2527,
"gzip": 1323,
"brotli": 1196
},
"total": {
"min": 2797,
"gzip": 1533,
"brotli": 1369
"min": 2731,
"gzip": 1503,
"brotli": 1349
}
},
{
"name": "comments",
"user": {
"min": 1216,
"gzip": 701,
"brotli": 639
"gzip": 704,
"brotli": 636
},
"runtime": {
"min": 7459,
"gzip": 3447,
"brotli": 3120
"min": 7393,
"gzip": 3423,
"brotli": 3103
},
"total": {
"min": 8675,
"gzip": 4148,
"brotli": 3759
"min": 8609,
"gzip": 4127,
"brotli": 3739
}
},
{
"name": "comments 💧",
"user": {
"min": 988,
"gzip": 590,
"brotli": 549
"gzip": 589,
"brotli": 572
},
"runtime": {
"min": 7980,
"gzip": 3684,
"brotli": 3336
"min": 7914,
"gzip": 3660,
"brotli": 3330
},
"total": {
"min": 8968,
"gzip": 4274,
"brotli": 3885
"min": 8902,
"gzip": 4249,
"brotli": 3902
}
}
]
Expand Down
56 changes: 23 additions & 33 deletions packages/runtime/src/dom/event.ts
Original file line number Diff line number Diff line change
@@ -1,56 +1,46 @@
type Unset = false | null | undefined;
type EventNames = keyof GlobalEventHandlersEventMap;

const delegationRoots = new WeakMap<
Node,
Map<string, WeakMap<Element, Unset | ((...args: any[]) => void)>>
const handlersByElement = new WeakMap<
Element,
undefined | ((...args: any[]) => void)
>();
const delegatedEventsByRoot = new WeakMap<Node, Set<string>>();

const eventOpts: AddEventListenerOptions = {
capture: true,
};
const eventOpts: AddEventListenerOptions = { capture: true };

export function on<
T extends EventNames,
H extends
| Unset
| false
| null
| undefined
| ((ev: GlobalEventHandlersEventMap[T], target: Element) => void),
>(element: Element, type: T, handler: H) {
const delegationRoot = element.getRootNode();
let delegationEvents = delegationRoots.get(delegationRoot);
if (!delegationEvents) {
delegationRoots.set(delegationRoot, (delegationEvents = new Map()));
}
let delegationHandlers = delegationEvents.get(type);
if (!delegationHandlers) {
delegationEvents!.set(type, (delegationHandlers = new WeakMap()));
delegationRoot.addEventListener(type, handleDelegated, eventOpts);
if (!handlersByElement.has(element)) {
const root = element.getRootNode();
const delegatedEvents = delegatedEventsByRoot.get(root);

if (!delegatedEvents) {
delegatedEventsByRoot.set(root, new Set([type]));
} else {
delegatedEvents.add(type);
}

root.addEventListener(type, handleDelegated, eventOpts);
}

delegationHandlers.set(element, handler);
handlersByElement.set(element, handler || undefined);
}

function handleDelegated(ev: GlobalEventHandlersEventMap[EventNames]) {
let target = ev.target as Element | null;
if (target) {
const delegationRoot = target.getRootNode();
const delegationEvents = delegationRoots.get(delegationRoot);
const delegationHandlers = delegationEvents!.get(ev.type!);

let handler = delegationHandlers!.get(target);
handlersByElement.get(target)?.(ev, target);

if (ev.bubbles) {
while (
!handler &&
!ev.cancelBubble &&
(target = target!.parentElement!)
) {
handler = delegationHandlers!.get(target);
while ((target = target.parentElement) && !ev.cancelBubble) {
handlersByElement.get(target)?.(ev, target);
}
}

if (handler) {
handler(ev, target);
}
}
}
4 changes: 3 additions & 1 deletion packages/runtime/src/dom/scope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ let debugID = 0;

export function createScope(context?: ScopeContext): Scope {
const scope = {} as Scope;
scope.___debugId = debugID++;
if (MARKO_DEBUG) {
scope.___debugId = debugID++;
}
scope.___client = true;
scope.___context = context;
return scope;
Expand Down

0 comments on commit 5ec47eb

Please sign in to comment.