From 12dd67ad802abe0af6d3ef594ffda2569154ca61 Mon Sep 17 00:00:00 2001 From: Michael Rawlings Date: Thu, 7 Oct 2021 21:45:53 -0700 Subject: [PATCH] feat: queue w/ argument, plus additional queue fixes --- .sizes.json | 6 +- packages/runtime/src/dom/control-flow.ts | 26 +++--- packages/runtime/src/dom/dom.ts | 7 +- packages/runtime/src/dom/index.ts | 7 +- packages/runtime/src/dom/queue.ts | 91 ++++++++++--------- packages/runtime/src/dom/renderer.ts | 15 ++- packages/runtime/src/dom/scope.ts | 21 +---- .../fixtures/batched-updates-cleanup/index.ts | 43 +++++---- .../dom/fixtures/batched-updates/index.ts | 38 +++++--- .../create-and-clear-rows-loop-in/index.ts | 5 +- .../fixtures/create-and-clear-rows/index.ts | 5 +- .../fixtures/move-and-clear-children/index.ts | 5 +- .../move-and-clear-top-level/index.ts | 5 +- .../dom/fixtures/remove-and-add-rows/index.ts | 5 +- .../switch-adjacent-only-children/index.ts | 5 +- .../fixtures/toggle-detached-state/index.ts | 31 +++++-- .../dom/fixtures/toggle-first-child/index.ts | 17 +++- .../dom/fixtures/toggle-last-child/index.ts | 17 +++- .../dom/fixtures/toggle-middle-child/index.ts | 17 +++- .../test/dom/fixtures/toggle-nested/index.ts | 53 ++++++++--- .../toggle-nested/snapshot.expected.md | 2 +- .../dom/fixtures/toggle-only-child/index.ts | 15 ++- .../test/dom/fixtures/update-attr/index.ts | 5 +- .../fixtures/update-dynamic-attrs/index.ts | 5 +- .../test/dom/fixtures/update-html/index.ts | 5 +- .../test/dom/fixtures/update-text/index.ts | 5 +- .../dom/fixtures/user-effect-cleanup/index.ts | 44 ++++++--- 27 files changed, 304 insertions(+), 196 deletions(-) diff --git a/.sizes.json b/.sizes.json index 10198cb94..5db8ff69b 100644 --- a/.sizes.json +++ b/.sizes.json @@ -6,9 +6,9 @@ { "name": "*", "individual": { - "min": 10028, - "gzip": 4392, - "brotli": 4033 + "min": 9986, + "gzip": 4401, + "brotli": 4020 } } ] diff --git a/packages/runtime/src/dom/control-flow.ts b/packages/runtime/src/dom/control-flow.ts index e2dd145ca..98ea73058 100644 --- a/packages/runtime/src/dom/control-flow.ts +++ b/packages/runtime/src/dom/control-flow.ts @@ -1,5 +1,6 @@ import { Context, setContext } from "../common/context"; import { Scope, ScopeOffsets } from "../common/types"; +import { queue } from "./queue"; import { reconcile } from "./reconcile"; import { Renderer, initRenderer } from "./renderer"; import { @@ -25,16 +26,19 @@ type Conditional = { [ConditionalIndex.CONTEXT]: typeof Context; }; -export function runInBranch( +export function queueInBranch( conditionalIndex: number, branch: Renderer, - fn: () => void + fn: () => void, + sortValue: number ) { if (read(conditionalIndex + ConditionalIndex.RENDERER) === branch) { - runWithScope( + queue( fn, - ScopeOffsets.BEGIN_DATA, - read(conditionalIndex + ConditionalIndex.SCOPE) as Scope + sortValue, + undefined, + read(conditionalIndex + ConditionalIndex.SCOPE) as Scope, + ScopeOffsets.BEGIN_DATA ); return 1; } @@ -109,8 +113,6 @@ export function setConditionalRenderer( prevScope.___getFirstNode() ); prevScope.___remove(); - - return newRenderer; } } @@ -139,8 +141,6 @@ export function setConditionalRendererOnlyChild( initRenderer(newRenderer, newScope); newScope.___insertBefore(referenceNode, null); setContext(null); - - return newRenderer; } } } @@ -165,11 +165,15 @@ type Loop = { [LoopIndex.CONTEXT]: typeof Context; }; -export function runForEach(loopIndex: number, fn: () => void) { +export function queueForEach( + loopIndex: number, + fn: () => void, + sortValue: number +) { for (const scope of read( loopIndex + LoopIndex.SCOPE_ARRAY )) { - runWithScope(fn, ScopeOffsets.BEGIN_DATA, scope); + queue(fn, sortValue, undefined, scope, ScopeOffsets.BEGIN_DATA); } } diff --git a/packages/runtime/src/dom/dom.ts b/packages/runtime/src/dom/dom.ts index 3723123c8..c7015a7a5 100644 --- a/packages/runtime/src/dom/dom.ts +++ b/packages/runtime/src/dom/dom.ts @@ -1,5 +1,6 @@ import { Renderer } from "./renderer"; import { onDestroy, Scope, ScopeOffsets, read, write } from "./scope"; +import { withQueueNext } from "./queue"; export const enum NodeType { Element = 1, @@ -206,9 +207,9 @@ function normalizeString(value: unknown) { type EffectFn = () => void | (() => void); export function userEffect(index: number, fn: EffectFn) { const cleanup = read(index) as ReturnType; - const nextCleanup = fn(); + const nextCleanup = withQueueNext(fn); if (cleanup) { - cleanup(); + withQueueNext(cleanup); } else { onDestroy(index); } @@ -223,7 +224,7 @@ export function lifecycle( ) { const mounted = read(index); if (!mounted) { - if (mount) mount(); + if (mount) withQueueNext(mount); onDestroy(index + 1); } if (mounted && update) update(); diff --git a/packages/runtime/src/dom/index.ts b/packages/runtime/src/dom/index.ts index 109ce98d5..75e79d9d0 100644 --- a/packages/runtime/src/dom/index.ts +++ b/packages/runtime/src/dom/index.ts @@ -3,7 +3,8 @@ export { setConditionalRendererOnlyChild, getConditionalFirstNode, getConditionalLastNode, - runInBranch, + queueInBranch, + queueForEach, setLoopOf, setLoopFromTo, setLoopIn, @@ -40,10 +41,8 @@ export { readInOwner, writeInOwner, bind, - writeQueued, runWithScope, - runInChild, - writeQueuedInOwner + runInChild } from "./scope"; export { Scope } from "../common/types"; diff --git a/packages/runtime/src/dom/queue.ts b/packages/runtime/src/dom/queue.ts index 548646ad1..5d58796e5 100644 --- a/packages/runtime/src/dom/queue.ts +++ b/packages/runtime/src/dom/queue.ts @@ -4,12 +4,11 @@ import { runWithScope, currentScope, currentOffset, - write, getOwnerScope, ownerOffset } from "./scope"; -type ExecFn = (scope: Scope, offset: number) => void; +type ExecFn = (...args: unknown[]) => void; const { port1, port2 } = new MessageChannel(); let queued: boolean; @@ -29,11 +28,21 @@ function triggerMacroTask() { } let queuedFns: unknown[] = []; -// [fn, scope, offset, sourceCount] +let queuedNext: unknown[] = []; + +const enum QueueOffsets { + FN = 0, + SCOPE = 1, + OFFSET = 2, + SORT_VALUE = 3, + ARGUMENT = 4, + TOTAL = 5 +} export function queue( fn: ExecFn, localIndex = 0, + argument: unknown = undefined, scope = currentScope, offset = currentOffset ) { @@ -42,9 +51,9 @@ export function queue( // index is where the function should be in the queue // but if it already exists, we should not add it again if ( - queuedFns[index] !== fn || - queuedFns[index + 1] !== scope || - queuedFns[index + 2] !== offset + queuedFns[index + QueueOffsets.FN] !== fn || + queuedFns[index + QueueOffsets.SCOPE] !== scope || + queuedFns[index + QueueOffsets.OFFSET] !== offset ) { if (!queued) { queued = true; @@ -52,80 +61,78 @@ export function queue( } for (let i = queuedFns.length - 1; i >= index; i--) { - queuedFns[i + 4] = queuedFns[i]; + queuedFns[i + QueueOffsets.TOTAL] = queuedFns[i]; } - queuedFns[index] = fn; - queuedFns[index + 1] = scope; - queuedFns[index + 2] = offset; - queuedFns[index + 3] = offset + localIndex; + queuedFns[index + QueueOffsets.FN] = fn; + queuedFns[index + QueueOffsets.SCOPE] = scope; + queuedFns[index + QueueOffsets.OFFSET] = offset; + queuedFns[index + QueueOffsets.SORT_VALUE] = offset + localIndex; } + queuedFns[index + QueueOffsets.ARGUMENT] = argument; } export function queueInOwner( fn: ExecFn, - sourceCount?: number, + localIndex?: number, + argument?: unknown, ownerLevel?: number ) { - queue(fn, sourceCount, getOwnerScope(ownerLevel), ownerOffset); + queue(fn, localIndex, argument, getOwnerScope(ownerLevel), ownerOffset); } -let queuedValues: unknown[] = []; -export function setQueued(scope: Scope, index: number, value: unknown) { - // TODO: if the same index is set twice for a scope, - // the first one should be removed from the queue - queuedValues.push(scope, index, value); +export function withQueueNext(fn: () => unknown) { + const current = queuedFns; + queuedFns = queuedNext; + const result = fn(); + queuedFns = current; + return result; } export function run() { if (queuedFns.length) { - const runningFns = queuedFns; - const runningValues = queuedValues; - queuedFns = []; - queuedValues = []; - for (let i = 0; i < runningValues.length; i += 3) { - write( - 0, - runningValues[i + 2] as unknown, - runningValues[i] as Scope, - runningValues[i + 1] as number - ); - } - for (let i = 0; i < runningFns.length; i += 4) { + for (let i = 0; i < queuedFns.length; i += QueueOffsets.TOTAL) { runWithScope( - runningFns[i] as ExecFn, - runningFns[i + 2] as number, - runningFns[i + 1] as Scope + queuedFns[i + QueueOffsets.FN] as ExecFn, + queuedFns[i + QueueOffsets.OFFSET] as number, + queuedFns[i + QueueOffsets.SCOPE] as Scope, + [queuedFns[i + QueueOffsets.ARGUMENT]] ); } + queuedFns = queuedNext; + queuedNext = []; } } -function findQueueIndex(scope: Scope, offset: number) { +function findQueueIndex(scope: Scope, sortValue: number) { let index = 0; - let max = queuedFns.length >>> 2; + let max = queuedFns.length / QueueOffsets.TOTAL; while (index < max) { const mid = (index + max) >>> 1; - const compareResult = compareQueue(mid * 4, scope, offset); + const compareResult = compareQueue( + mid * QueueOffsets.TOTAL, + scope, + sortValue + ); if (compareResult > 0) { max = mid; } else if (compareResult < 0) { index = mid + 1; } else { - return mid * 4; + return mid * QueueOffsets.TOTAL; } } - return index * 4; + return index * QueueOffsets.TOTAL; } -function compareQueue(index: number, scope: Scope, offset: number) { +function compareQueue(index: number, scope: Scope, sortValue: number) { return ( compare( - (queuedFns[index + 1] as Scope)[ScopeOffsets.ID], + (queuedFns[index + QueueOffsets.SCOPE] as Scope)[ScopeOffsets.ID], scope[ScopeOffsets.ID] - ) || (queuedFns[index + 3] as number) - offset + ) || (queuedFns[index + QueueOffsets.SORT_VALUE] as number) - sortValue ); } diff --git a/packages/runtime/src/dom/renderer.ts b/packages/runtime/src/dom/renderer.ts index f3dd590c2..030978cfd 100644 --- a/packages/runtime/src/dom/renderer.ts +++ b/packages/runtime/src/dom/renderer.ts @@ -2,6 +2,7 @@ import { ScopeOffsets } from "../common/types"; import { DOMMethods, staticNodeMethods } from "./dom"; import { createScope, Scope, runWithScope } from "./scope"; import { WalkCodes, walk, trimWalkString } from "./walker"; +import { queue, run } from "./queue"; const enum NodeType { Element = 1, @@ -82,12 +83,18 @@ export function createRenderFn( return (input: I): RenderResult => { const scope = createScope(size!, domMethods!); const dom = initRenderer(renderer, scope) as RenderResult; - dynamicInput && - runWithScope(dynamicInput, ScopeOffsets.BEGIN_DATA, scope, [input]); + + if (dynamicInput) { + queue(dynamicInput, -1, input, scope, ScopeOffsets.BEGIN_DATA); + } + + run(); dom.update = (newInput: I) => { - dynamicInput && - runWithScope(dynamicInput, ScopeOffsets.BEGIN_DATA, scope, [newInput]); + if (dynamicInput) { + queue(dynamicInput, -1, newInput, scope, ScopeOffsets.BEGIN_DATA); + run(); + } }; dom.destroy = () => { diff --git a/packages/runtime/src/dom/scope.ts b/packages/runtime/src/dom/scope.ts index dda7a0d0b..ad3794399 100644 --- a/packages/runtime/src/dom/scope.ts +++ b/packages/runtime/src/dom/scope.ts @@ -1,5 +1,5 @@ import { DOMMethods, staticNodeMethods } from "./dom"; -import { setQueued } from "./queue"; +import { withQueueNext } from "./queue"; import { Scope, ScopeOffsets } from "../common/types"; export { Scope, ScopeOffsets }; @@ -105,23 +105,6 @@ export function runInChild(fn: () => void, offset: number) { } } -export function writeQueued( - localIndex: number, - value: unknown, - scope = currentScope, - offset = currentOffset -) { - setQueued(scope, offset + localIndex, value); -} - -export function writeQueuedInOwner( - localIndex: number, - value: unknown, - ownerLevel?: number -) { - writeQueued(localIndex, value, getOwnerScope(ownerLevel), ownerOffset); -} - export function destroyScope(scope: Scope) { scope[ScopeOffsets.OWNER_SCOPE]?.[ScopeOffsets.CLEANUP]?.delete(scope); @@ -129,7 +112,7 @@ export function destroyScope(scope: Scope) { if (cleanup) { for (const instance of cleanup) { if (typeof instance === "number") { - (scope[instance] as () => void)(); + withQueueNext(scope[instance] as () => void); } else { destroyScope(instance); } diff --git a/packages/runtime/test/dom/fixtures/batched-updates-cleanup/index.ts b/packages/runtime/test/dom/fixtures/batched-updates-cleanup/index.ts index 96ae9f2b7..f499a6130 100644 --- a/packages/runtime/test/dom/fixtures/batched-updates-cleanup/index.ts +++ b/packages/runtime/test/dom/fixtures/batched-updates-cleanup/index.ts @@ -11,7 +11,7 @@ import { read, bind, readInOwner, - runInBranch + queueInBranch } from "../../../../src/dom/index"; import { get, next, over, open, close } from "../../utils/walks"; @@ -46,10 +46,8 @@ type scope = { export const template = ``; export const walks = open(7) + get + over(1) + get + over(1) + close; export const render = () => { - write(Index.SHOW, true); - write(Index.MESSAGE, "hi"); - execShow(); - execMessage(); + execShow(true); + execMessage("hi"); hydrate(); }; @@ -58,23 +56,25 @@ export const hydrate = register("", () => { }); const clickHandler = () => { - if (write(Index.MESSAGE, "bye")) { - queue(execMessage, 6); - } - if (write(Index.SHOW, !read(Index.SHOW))) { - queue(execShow, 5); + queue(execMessage, Index.MESSAGE, "bye"); + queue(execShow, Index.SHOW, !read(Index.SHOW)); +}; + +const execShow = value => { + if (write(Index.SHOW, value)) { + setConditionalRenderer(Index.CONDITIONAL, value ? branch0 : undefined); } }; -const execShow = () => { - setConditionalRenderer( - Index.CONDITIONAL, - read(Index.SHOW) ? branch0 : undefined - ); -}; - -const execMessage = () => { - runInBranch(Index.CONDITIONAL, branch0, execMessageBranch0); +const execMessage = value => { + if (write(Index.MESSAGE, value)) { + queueInBranch( + Index.CONDITIONAL, + branch0, + execMessageBranch0, + Branch0Index.CLOSURE_MESSAGE + ); + } }; const execMessageBranch0 = () => { @@ -86,6 +86,7 @@ export default createRenderFn(template, walks, render, 0); ensureDelegated("click"); const enum Branch0Index { + CLOSURE_MESSAGE = -1, TEXT = 0 } @@ -94,6 +95,8 @@ type Branch0Scope = [Text]; const branch0 = createRenderer( " ", next(1) + get + next(1), - undefined, + () => { + queue(execMessageBranch0, Branch0Index.CLOSURE_MESSAGE); + }, 0 ); diff --git a/packages/runtime/test/dom/fixtures/batched-updates/index.ts b/packages/runtime/test/dom/fixtures/batched-updates/index.ts index ce794bbc5..23512d73f 100644 --- a/packages/runtime/test/dom/fixtures/batched-updates/index.ts +++ b/packages/runtime/test/dom/fixtures/batched-updates/index.ts @@ -21,7 +21,8 @@ const enum Index { BUTTON = 0, TEXT = 1, A = 2, - B = 3 + B = 3, + SUM_AB = 4 } type scope = { @@ -29,6 +30,7 @@ type scope = { [Index.TEXT]: Text; [Index.A]: number; [Index.B]: number; + [Index.SUM_AB]: number; }; // @@ -38,9 +40,8 @@ type scope = { export const template = ``; export const walks = open(4) + get + next(1) + get + next(1) + close; export const render = () => { - write(Index.A, 0); - write(Index.B, 0); - execAB(); + execA(0); + execB(0); hydrate(); }; @@ -49,19 +50,30 @@ export const hydrate = register("", () => { }); const clickHandler = () => { - if ( - write(Index.A, read(Index.A) + 1) | - write(Index.B, read(Index.B) + 1) - ) { - queue(execAB); + queue(execA, Index.A, read(Index.A) + 1); + queue(execB, Index.B, read(Index.B) + 1); +}; + +const execA = (value: number) => { + if (write(Index.A, value)) { + queue(execAB, Index.SUM_AB); + } +}; + +const execB = (value: number) => { + if (write(Index.B, value)) { + queue(execAB, Index.SUM_AB); } }; const execAB = () => { - data( - Index.TEXT, - read(Index.A) + read(Index.B) - ); + execSumAB(read(Index.A) + read(Index.B)); +}; + +const execSumAB = (value: number) => { + if (write(Index.SUM_AB, value)) { + data(Index.TEXT, value); + } }; export default createRenderFn(template, walks, render, 0); diff --git a/packages/runtime/test/dom/fixtures/create-and-clear-rows-loop-in/index.ts b/packages/runtime/test/dom/fixtures/create-and-clear-rows-loop-in/index.ts index 818a26273..8a5a676be 100644 --- a/packages/runtime/test/dom/fixtures/create-and-clear-rows-loop-in/index.ts +++ b/packages/runtime/test/dom/fixtures/create-and-clear-rows-loop-in/index.ts @@ -61,8 +61,9 @@ export const execInputChildren = () => { }; export const execDynamicInput = (input: Input) => { - write(Index.INPUT_CHILDREN, input.children); - execInputChildren(); + if (write(Index.INPUT_CHILDREN, input.children)) { + execInputChildren(); + } }; export default createRenderFn(template, walks, undefined, 0, execDynamicInput); diff --git a/packages/runtime/test/dom/fixtures/create-and-clear-rows/index.ts b/packages/runtime/test/dom/fixtures/create-and-clear-rows/index.ts index 14e1c1d8e..df6e0246b 100644 --- a/packages/runtime/test/dom/fixtures/create-and-clear-rows/index.ts +++ b/packages/runtime/test/dom/fixtures/create-and-clear-rows/index.ts @@ -80,8 +80,9 @@ export const execInputChildren = () => { }; export const execDynamicInput = (input: Input) => { - write(Index.INPUT_CHILDREN, input.children); - execInputChildren(); + if (write(Index.INPUT_CHILDREN, input.children)) { + execInputChildren(); + } }; export default createRenderFn(template, walks, undefined, 0, execDynamicInput); diff --git a/packages/runtime/test/dom/fixtures/move-and-clear-children/index.ts b/packages/runtime/test/dom/fixtures/move-and-clear-children/index.ts index 2fbecad5c..2e24e81db 100644 --- a/packages/runtime/test/dom/fixtures/move-and-clear-children/index.ts +++ b/packages/runtime/test/dom/fixtures/move-and-clear-children/index.ts @@ -80,8 +80,9 @@ export const execInputChildren = () => { }; export const execDynamicInput = (input: Input) => { - write(Index.INPUT_CHILDREN, input.children); - execInputChildren(); + if (write(Index.INPUT_CHILDREN, input.children)) { + execInputChildren(); + } }; export default createRenderFn(template, walks, undefined, 0, execDynamicInput); diff --git a/packages/runtime/test/dom/fixtures/move-and-clear-top-level/index.ts b/packages/runtime/test/dom/fixtures/move-and-clear-top-level/index.ts index 9489dd743..0cc8a36e7 100644 --- a/packages/runtime/test/dom/fixtures/move-and-clear-top-level/index.ts +++ b/packages/runtime/test/dom/fixtures/move-and-clear-top-level/index.ts @@ -78,8 +78,9 @@ export const execInputChildren = () => { }; export const execDynamicInput = (input: Input) => { - write(Index.INPUT_CHILDREN, input.children); - execInputChildren(); + if (write(Index.INPUT_CHILDREN, input.children)) { + execInputChildren(); + } }; export default createRenderFn(template, walks, undefined, 0, execDynamicInput); diff --git a/packages/runtime/test/dom/fixtures/remove-and-add-rows/index.ts b/packages/runtime/test/dom/fixtures/remove-and-add-rows/index.ts index 52ac8db4f..c3ee09c92 100644 --- a/packages/runtime/test/dom/fixtures/remove-and-add-rows/index.ts +++ b/packages/runtime/test/dom/fixtures/remove-and-add-rows/index.ts @@ -85,8 +85,9 @@ export const execInputChildren = () => { }; export const execDynamicInput = (input: Input) => { - write(Index.INPUT_CHILDREN, input.children); - execInputChildren(); + if (write(Index.INPUT_CHILDREN, input.children)) { + execInputChildren(); + } }; export default createRenderFn(template, walks, undefined, 0, execDynamicInput); diff --git a/packages/runtime/test/dom/fixtures/switch-adjacent-only-children/index.ts b/packages/runtime/test/dom/fixtures/switch-adjacent-only-children/index.ts index 47eb3dc06..38dd41df9 100644 --- a/packages/runtime/test/dom/fixtures/switch-adjacent-only-children/index.ts +++ b/packages/runtime/test/dom/fixtures/switch-adjacent-only-children/index.ts @@ -81,8 +81,9 @@ export const execInputChildren = () => { }; export const execDynamicInput = (input: Input) => { - write(Index.INPUT_CHILDREN, input.children); - execInputChildren(); + if (write(Index.INPUT_CHILDREN, input.children)) { + execInputChildren(); + } }; export default createRenderFn(template, walks, undefined, 0, execDynamicInput); diff --git a/packages/runtime/test/dom/fixtures/toggle-detached-state/index.ts b/packages/runtime/test/dom/fixtures/toggle-detached-state/index.ts index 2b16d4cd4..a039950bf 100644 --- a/packages/runtime/test/dom/fixtures/toggle-detached-state/index.ts +++ b/packages/runtime/test/dom/fixtures/toggle-detached-state/index.ts @@ -2,11 +2,12 @@ import { data, read, write, + queue, readInOwner, setConditionalRenderer, createRenderer, createRenderFn, - runInBranch + queueInBranch } from "../../../../src/dom/index"; import { next, get, over, open, close } from "../../utils/walks"; @@ -50,15 +51,23 @@ type scope = { export const template = `
`; export const walks = open(6) + next(1) + get + over(1) + close; -export const execInputValue = () => { +export const execInputVisible = () => { setConditionalRenderer( Index.CONDITIONAL, read(Index.INPUT_VISIBLE) ? branch0 : undefined ); - runInBranch(Index.CONDITIONAL, branch0, execInputBranch0); }; -function execInputBranch0() { +export const execInputValue = () => { + queueInBranch( + Index.CONDITIONAL, + branch0, + execInputValueBranch0, + Branch0Index.CLOSURE_VALUE + ); +}; + +function execInputValueBranch0() { data( Branch0Index.TEXT, readInOwner(Index.INPUT_VALUE)!.name @@ -66,14 +75,18 @@ function execInputBranch0() { } export const execDynamicInput = (input: typeof inputs[number]) => { - write(Index.INPUT_VISIBLE, input.visible); - write(Index.INPUT_VALUE, input.value); - execInputValue(); + if (write(Index.INPUT_VISIBLE, input.visible)) { + execInputVisible(); + } + if (write(Index.INPUT_VALUE, input.value)) { + execInputValue(); + } }; export default createRenderFn(template, walks, undefined, 0, execDynamicInput); const enum Branch0Index { + CLOSURE_VALUE = -1, TEXT = 0 } @@ -82,6 +95,8 @@ type Branch0Scope = [Text]; const branch0 = createRenderer( " ", open(1) + next(1) + get + next(1) + close, - undefined, + () => { + queue(execInputValueBranch0, Branch0Index.CLOSURE_VALUE); + }, 0 ); diff --git a/packages/runtime/test/dom/fixtures/toggle-first-child/index.ts b/packages/runtime/test/dom/fixtures/toggle-first-child/index.ts index cb1269297..16245016b 100644 --- a/packages/runtime/test/dom/fixtures/toggle-first-child/index.ts +++ b/packages/runtime/test/dom/fixtures/toggle-first-child/index.ts @@ -6,7 +6,7 @@ import { createRenderer, createRenderFn, readInOwner, - runInBranch + queueInBranch } from "../../../../src/dom/index"; import { next, over, get, open, close } from "../../utils/walks"; @@ -53,7 +53,12 @@ export const execInputValue = () => { Index.CONDITIONAL, read(Index.INPUT_VALUE) ? branch0 : undefined ); - runInBranch(Index.CONDITIONAL, branch0, execInputBranch0); + queueInBranch( + Index.CONDITIONAL, + branch0, + execInputBranch0, + Branch0Index.CLOSURE_VALUE + ); }; function execInputBranch0() { @@ -64,13 +69,15 @@ function execInputBranch0() { } export const execDynamicInput = (input: typeof inputs[number]) => { - write(Index.INPUT_VALUE, input.value); - execInputValue(); + if (write(Index.INPUT_VALUE, input.value)) { + execInputValue(); + } }; export default createRenderFn(template, walks, undefined, 0, execDynamicInput); const enum Branch0Index { + CLOSURE_VALUE = -1, TEXT = 0 } @@ -79,6 +86,6 @@ type Branch0Scope = [Text]; const branch0 = createRenderer( " ", open(1) + next(1) + get + next(1) + close, - undefined, + undefined, // optimization 0 ); diff --git a/packages/runtime/test/dom/fixtures/toggle-last-child/index.ts b/packages/runtime/test/dom/fixtures/toggle-last-child/index.ts index 4f67399a5..1ca36832e 100644 --- a/packages/runtime/test/dom/fixtures/toggle-last-child/index.ts +++ b/packages/runtime/test/dom/fixtures/toggle-last-child/index.ts @@ -6,7 +6,7 @@ import { createRenderer, createRenderFn, readInOwner, - runInBranch + queueInBranch } from "../../../../src/dom/index"; import { next, over, get, open, close } from "../../utils/walks"; @@ -53,7 +53,12 @@ export const execInputValue = () => { Index.CONDITIONAL, read(Index.INPUT_VALUE) ? branch0 : undefined ); - runInBranch(Index.CONDITIONAL, branch0, execInputBranch0); + queueInBranch( + Index.CONDITIONAL, + branch0, + execInputBranch0, + Branch0Index.CLOSURE_VALUE + ); }; function execInputBranch0() { @@ -64,13 +69,15 @@ function execInputBranch0() { } export const execDynamicInput = (input: typeof inputs[number]) => { - write(Index.INPUT_VALUE, input.value); - execInputValue(); + if (write(Index.INPUT_VALUE, input.value)) { + execInputValue(); + } }; export default createRenderFn(template, walks, undefined, 0, execDynamicInput); const enum Branch0Index { + CLOSURE_VALUE = -1, TEXT = 0 } @@ -79,6 +86,6 @@ type Branch0Scope = [Text]; const branch0 = createRenderer( " ", open(1) + next(1) + get + next(1) + close, - undefined, + undefined, // optimization 0 ); diff --git a/packages/runtime/test/dom/fixtures/toggle-middle-child/index.ts b/packages/runtime/test/dom/fixtures/toggle-middle-child/index.ts index 1cfe025c1..edef75a84 100644 --- a/packages/runtime/test/dom/fixtures/toggle-middle-child/index.ts +++ b/packages/runtime/test/dom/fixtures/toggle-middle-child/index.ts @@ -6,7 +6,7 @@ import { createRenderer, createRenderFn, readInOwner, - runInBranch + queueInBranch } from "../../../../src/dom/index"; import { next, over, get, open, close } from "../../utils/walks"; @@ -53,7 +53,12 @@ export const execInputValue = () => { Index.CONDITIONAL, read(Index.INPUT_VALUE) ? branch0 : undefined ); - runInBranch(Index.CONDITIONAL, branch0, execInputBranch0); + queueInBranch( + Index.CONDITIONAL, + branch0, + execInputBranch0, + Branch0Index.CLOSURE_VALUE + ); }; function execInputBranch0() { @@ -64,13 +69,15 @@ function execInputBranch0() { } export const execDynamicInput = (input: typeof inputs[number]) => { - write(Index.INPUT_VALUE, input.value); - execInputValue(); + if (write(Index.INPUT_VALUE, input.value)) { + execInputValue(); + } }; export default createRenderFn(template, walks, undefined, 0, execDynamicInput); const enum Branch0Index { + CLOSURE_VALUE = -1, TEXT = 0 } @@ -79,6 +86,6 @@ type Branch0Scope = [Text]; const branch0 = createRenderer( " ", open(1) + next(1) + get + next(1) + close, - undefined, + undefined, // optimization 0 ); diff --git a/packages/runtime/test/dom/fixtures/toggle-nested/index.ts b/packages/runtime/test/dom/fixtures/toggle-nested/index.ts index cf4a3d0c8..82cd31471 100644 --- a/packages/runtime/test/dom/fixtures/toggle-nested/index.ts +++ b/packages/runtime/test/dom/fixtures/toggle-nested/index.ts @@ -8,8 +8,9 @@ import { getConditionalLastNode, write, read, + queue, readInOwner, - runInBranch + queueInBranch } from "../../../../src/dom/index"; import { next, over, get, open, close, skip } from "../../utils/walks"; @@ -70,19 +71,19 @@ export const template = `
`; export const walks = open(7) + next(1) + get + over(1) + close; export const execInputShow = () => { - if ( - setConditionalRenderer( - Index.CONDITIONAL, - read(Index.INPUT_SHOW) ? branch0 : undefined - ) - ) { - runInBranch(Index.CONDITIONAL, branch0, execInputValue1Branch0); - runInBranch(Index.CONDITIONAL, branch0, execInputValue2Branch0); - } + setConditionalRenderer( + Index.CONDITIONAL, + read(Index.INPUT_SHOW) ? branch0 : undefined + ); }; export const execInputValue1 = () => { - runInBranch(Index.CONDITIONAL, branch0, execInputValue1Branch0); + queueInBranch( + Index.CONDITIONAL, + branch0, + execInputValue1Branch0, + Branch0Index.CLOSURE_VALUE1 + ); }; export const execInputValue1Branch0 = () => { @@ -90,11 +91,21 @@ export const execInputValue1Branch0 = () => { Branch0Index.CONDITIONAL1, readInOwner(Index.INPUT_VALUE1) ? branch0_0 : undefined ); - runInBranch(Branch0Index.CONDITIONAL1, branch0_0, execInputValue1Branch0_0); + queueInBranch( + Branch0Index.CONDITIONAL1, + branch0_0, + execInputValue1Branch0_0, + Branch0_0Index.CLOSURE_VALUE1 + ); }; export const execInputValue2 = () => { - runInBranch(Index.CONDITIONAL, branch0, execInputValue2Branch0); + queueInBranch( + Index.CONDITIONAL, + branch0, + execInputValue2Branch0, + Branch0Index.CLOSURE_VALUE2 + ); }; export const execInputValue2Branch0 = () => { @@ -102,7 +113,12 @@ export const execInputValue2Branch0 = () => { Branch0Index.CONDITIONAL2, readInOwner(Index.INPUT_VALUE2) ? branch0_1 : undefined ); - runInBranch(Branch0Index.CONDITIONAL2, branch0_1, execInputValue2Branch0_1); + queueInBranch( + Branch0Index.CONDITIONAL2, + branch0_1, + execInputValue2Branch0_1, + Branch0_1Index.CLOSURE_VALUE2 + ); }; const execInputValue1Branch0_0 = () => { @@ -122,6 +138,8 @@ export const execDynamicInput = (input: Input) => { export default createRenderFn(template, walks, undefined, 0, execDynamicInput); const enum Branch0Index { + CLOSURE_VALUE1 = -2, + CLOSURE_VALUE2 = -1, COMMENT1 = 0, CONDITIONAL1 = 0, COMMENT2 = 4, @@ -138,7 +156,10 @@ type Branch0Scope = { const branch0 = createRenderer( "", open(8) + get + over(1) + skip(3) + get + over(1) + close, - undefined, + () => { + queue(execInputValue1Branch0, Branch0Index.CLOSURE_VALUE1); + queue(execInputValue2Branch0, Branch0Index.CLOSURE_VALUE2); + }, 0, 0, fragmentMethods, @@ -149,6 +170,7 @@ const branch0 = createRenderer( ); const enum Branch0_0Index { + CLOSURE_VALUE1 = -1, TEXT = 0 } @@ -164,6 +186,7 @@ const branch0_0 = createRenderer( ); const enum Branch0_1Index { + CLOSURE_VALUE2 = -1, TEXT = 0 } diff --git a/packages/runtime/test/dom/fixtures/toggle-nested/snapshot.expected.md b/packages/runtime/test/dom/fixtures/toggle-nested/snapshot.expected.md index 5de6e0d79..e764c42d4 100644 --- a/packages/runtime/test/dom/fixtures/toggle-nested/snapshot.expected.md +++ b/packages/runtime/test/dom/fixtures/toggle-nested/snapshot.expected.md @@ -30,9 +30,9 @@ inserted #comment removed #comment after #comment inserted div0/span0 removed #comment after div0/span0 -div0/span0/#text0: " " => "Hello" inserted div0/span1 removed #comment after div0/span1 +div0/span0/#text0: " " => "Hello" div0/span1/#text0: " " => "World" ``` diff --git a/packages/runtime/test/dom/fixtures/toggle-only-child/index.ts b/packages/runtime/test/dom/fixtures/toggle-only-child/index.ts index 9c911b0f7..6be7a6d5f 100644 --- a/packages/runtime/test/dom/fixtures/toggle-only-child/index.ts +++ b/packages/runtime/test/dom/fixtures/toggle-only-child/index.ts @@ -6,7 +6,7 @@ import { read, write, readInOwner, - runInBranch + queueInBranch } from "../../../../src/dom/index"; import { get, next, over, open, close } from "../../utils/walks"; @@ -51,7 +51,12 @@ export const execInputValue = () => { Index.CONDITIONAL, read(Index.INPUT_VALUE) ? branch0 : undefined ); - runInBranch(Index.CONDITIONAL, branch0, execInputBranch0); + queueInBranch( + Index.CONDITIONAL, + branch0, + execInputBranch0, + Branch0Index.CLOSURE_VALUE + ); }; function execInputBranch0() { @@ -62,13 +67,15 @@ function execInputBranch0() { } export const execDynamicInput = (input: typeof inputs[number]) => { - write(Index.INPUT_VALUE, input.value); - execInputValue(); + if (write(Index.INPUT_VALUE, input.value)) { + execInputValue(); + } }; export default createRenderFn(template, walks, undefined, 0, execDynamicInput); const enum Branch0Index { + CLOSURE_VALUE = -1, TEXT = 0 } diff --git a/packages/runtime/test/dom/fixtures/update-attr/index.ts b/packages/runtime/test/dom/fixtures/update-attr/index.ts index 97449c975..90dea5caf 100644 --- a/packages/runtime/test/dom/fixtures/update-attr/index.ts +++ b/packages/runtime/test/dom/fixtures/update-attr/index.ts @@ -41,8 +41,9 @@ export const execInputValue = () => { }; export const execDynamicInput = (input: typeof inputs[number]) => { - write(Index.INPUT_VALUE, input.value); - execInputValue(); + if (write(Index.INPUT_VALUE, input.value)) { + execInputValue(); + } }; export default createRenderFn(template, walks, undefined, 0, execDynamicInput); diff --git a/packages/runtime/test/dom/fixtures/update-dynamic-attrs/index.ts b/packages/runtime/test/dom/fixtures/update-dynamic-attrs/index.ts index 7c4088a33..50343b046 100644 --- a/packages/runtime/test/dom/fixtures/update-dynamic-attrs/index.ts +++ b/packages/runtime/test/dom/fixtures/update-dynamic-attrs/index.ts @@ -38,8 +38,9 @@ export const execInputValue = () => { }; export const execDynamicInput = (input: typeof inputs[number]) => { - write(Index.INPUT_VALUE, input.value); - execInputValue(); + if (write(Index.INPUT_VALUE, input.value)) { + execInputValue(); + } }; export default createRenderFn(template, walks, undefined, 0, execDynamicInput); diff --git a/packages/runtime/test/dom/fixtures/update-html/index.ts b/packages/runtime/test/dom/fixtures/update-html/index.ts index 66ff5a55a..8150d9aba 100644 --- a/packages/runtime/test/dom/fixtures/update-html/index.ts +++ b/packages/runtime/test/dom/fixtures/update-html/index.ts @@ -34,8 +34,9 @@ export const execInputValue = () => { }; export const execDynamicInput = (input: typeof inputs[number]) => { - write(Index.INPUT_VALUE, input.value); - execInputValue(); + if (write(Index.INPUT_VALUE, input.value)) { + execInputValue(); + } }; export default createRenderFn(template, walks, undefined, 0, execDynamicInput); diff --git a/packages/runtime/test/dom/fixtures/update-text/index.ts b/packages/runtime/test/dom/fixtures/update-text/index.ts index f4c4b68ed..d287710dd 100644 --- a/packages/runtime/test/dom/fixtures/update-text/index.ts +++ b/packages/runtime/test/dom/fixtures/update-text/index.ts @@ -32,8 +32,9 @@ export const execInputValue = () => { }; export const execDynamicInput = (input: typeof inputs[number]) => { - write(Index.INPUT_VALUE, input.value); - execInputValue(); + if (write(Index.INPUT_VALUE, input.value)) { + execInputValue(); + } }; export default createRenderFn(template, walks, undefined, 0, execDynamicInput); diff --git a/packages/runtime/test/dom/fixtures/user-effect-cleanup/index.ts b/packages/runtime/test/dom/fixtures/user-effect-cleanup/index.ts index dab7a9161..e9a4e1a75 100644 --- a/packages/runtime/test/dom/fixtures/user-effect-cleanup/index.ts +++ b/packages/runtime/test/dom/fixtures/user-effect-cleanup/index.ts @@ -10,14 +10,15 @@ import { import { wait } from "../../../utils/resolve"; import { get, next, open, close } from "../../utils/walks"; -export const inputs = [{ value: 0 }, wait(2), { value: 1 }, wait(2)] as const; +export const inputs = [{ value: 0 }, wait(4), { value: 1 }, wait(4)] as const; const enum Index { DIV_TEXT = 0, INPUT_VALUE = 1, A = 2, B = 3, - EFFECT_CLEANUP = 4 + CONCAT_AB = 4, + EFFECT_CLEANUP = 5 } type scope = { @@ -25,6 +26,7 @@ type scope = { [Index.INPUT_VALUE]: typeof inputs[0 | 2]["value"]; [Index.A]: number; [Index.B]: number; + [Index.CONCAT_AB]: string; [Index.EFFECT_CLEANUP]: () => void; }; @@ -38,13 +40,30 @@ type scope = { export const template = `
`; export const walks = open(5) + next(1) + get + next(1) + close; export const render = () => { - write(Index.A, 0); - write(Index.B, 0); - execAB(); + execA(0); + execB(0); }; +function execA(value) { + if (write(Index.A, value)) { + queue(execAB, Index.CONCAT_AB); + } +} + +function execB(value) { + if (write(Index.B, value)) { + queue(execAB, Index.CONCAT_AB); + } +} + function execAB() { - data(Index.DIV_TEXT, "" + read(Index.A) + read(Index.B)); + execConcatAB("" + read(Index.A) + read(Index.B)); +} + +function execConcatAB(value) { + if (write(Index.CONCAT_AB, value)) { + data(Index.DIV_TEXT, value); + } } export const hydrateInputValue = () => { @@ -53,19 +72,16 @@ export const hydrateInputValue = () => { const effectFn = () => { const previousValue = read(Index.INPUT_VALUE) + 1; - if (write(Index.A, previousValue)) { - queue(execAB); - } + queue(execA, Index.A, previousValue); return bind(() => { - if (write(Index.B, previousValue)) { - queue(execAB); - } + queue(execB, Index.B, previousValue); }); }; export const execDynamicInput = (input: typeof inputs[0]) => { - write(Index.INPUT_VALUE, input.value); - hydrateInputValue(); + if (write(Index.INPUT_VALUE, input.value)) { + hydrateInputValue(); + } }; export default createRenderFn(template, walks, render, 0, execDynamicInput);