feat: queue w/ argument, plus additional queue fixes

This commit is contained in:
Michael Rawlings 2021-10-07 21:45:53 -07:00
parent a0e59440cb
commit 12dd67ad80
No known key found for this signature in database
GPG Key ID: B9088328804D407C
27 changed files with 304 additions and 196 deletions

View File

@ -6,9 +6,9 @@
{
"name": "*",
"individual": {
"min": 10028,
"gzip": 4392,
"brotli": 4033
"min": 9986,
"gzip": 4401,
"brotli": 4020
}
}
]

View File

@ -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<Loop, LoopIndex.SCOPE_ARRAY>(
loopIndex + LoopIndex.SCOPE_ARRAY
)) {
runWithScope(fn, ScopeOffsets.BEGIN_DATA, scope);
queue(fn, sortValue, undefined, scope, ScopeOffsets.BEGIN_DATA);
}
}

View File

@ -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<EffectFn>;
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();

View File

@ -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";

View File

@ -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
);
}

View File

@ -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<I extends Input>(
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 = () => {

View File

@ -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);
}

View File

@ -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 = `<button></button><!>`;
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(
"<span> </span>",
next(1) + get + next(1),
undefined,
() => {
queue(execMessageBranch0, Branch0Index.CLOSURE_MESSAGE);
},
0
);

View File

@ -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;
};
// <let/a = 0/>
@ -38,9 +40,8 @@ type scope = {
export const template = `<button> </button>`;
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<scope, Index.A>(Index.A) + 1) |
write(Index.B, read<scope, Index.B>(Index.B) + 1)
) {
queue(execAB);
queue(execA, Index.A, read<scope, Index.A>(Index.A) + 1);
queue(execB, Index.B, read<scope, Index.B>(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<scope, Index.A>(Index.A) + read<scope, Index.B>(Index.B)
);
execSumAB(read<scope, Index.A>(Index.A) + read<scope, Index.B>(Index.B));
};
const execSumAB = (value: number) => {
if (write(Index.SUM_AB, value)) {
data(Index.TEXT, value);
}
};
export default createRenderFn(template, walks, render, 0);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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 = `<div><!></div>`;
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<scope, Index.INPUT_VALUE>(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(
"<span> </span>",
open(1) + next(1) + get + next(1) + close,
undefined,
() => {
queue(execInputValueBranch0, Branch0Index.CLOSURE_VALUE);
},
0
);

View File

@ -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(
"<span> </span>",
open(1) + next(1) + get + next(1) + close,
undefined,
undefined, // optimization
0
);

View File

@ -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(
"<span> </span>",
open(1) + next(1) + get + next(1) + close,
undefined,
undefined, // optimization
0
);

View File

@ -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(
"<span> </span>",
open(1) + next(1) + get + next(1) + close,
undefined,
undefined, // optimization
0
);

View File

@ -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 = `<div><!></div>`;
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
}

View File

@ -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"
```

View File

@ -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
}

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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 = `<div> </div>`;
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<scope, Index.INPUT_VALUE>(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);