Optimized for

This commit is contained in:
2026-04-03 21:22:25 +02:00
parent 29c6451706
commit 6a51c9ef9b
3 changed files with 48 additions and 40 deletions

42
dist/sigpro.js vendored
View File

@@ -277,21 +277,23 @@
const append = (child) => { const append = (child) => {
if (Array.isArray(child)) if (Array.isArray(child))
return child.forEach(append); return child.forEach(append);
if (typeof child === "function") { if (child instanceof Node) {
el.appendChild(child);
} else if (typeof child === "function") {
const marker = document.createTextNode(""); const marker = document.createTextNode("");
el.appendChild(marker); el.appendChild(marker);
let nodes = []; let nodes = [];
el._cleanups.add($watch(() => { el._cleanups.add($watch(() => {
const result = child(), nextNodes = (Array.isArray(result) ? result : [result]).map((item) => item?._isRuntime ? item.container : item instanceof Node ? item : document.createTextNode(item ?? "")); const res = child(), next = (Array.isArray(res) ? res : [res]).map((i) => i?._isRuntime ? i.container : i instanceof Node ? i : document.createTextNode(i ?? ""));
nodes.forEach((node) => { nodes.forEach((n) => {
sweep(node); sweep(n);
node.remove(); n.remove();
}); });
nextNodes.forEach((node) => marker.parentNode?.insertBefore(node, marker)); next.forEach((n) => marker.parentNode?.insertBefore(n, marker));
nodes = nextNodes; nodes = next;
})); }));
} else } else
el.appendChild(child instanceof Node ? child : document.createTextNode(child ?? "")); el.appendChild(document.createTextNode(child ?? ""));
}; };
append(content); append(content);
return el; return el;
@@ -317,38 +319,40 @@
}; };
$if.not = (condition, thenVal, otherwiseVal) => $if(() => !(typeof condition === "function" ? condition() : condition), thenVal, otherwiseVal); $if.not = (condition, thenVal, otherwiseVal) => $if(() => !(typeof condition === "function" ? condition() : condition), thenVal, otherwiseVal);
var $for = (source, render, keyFn) => { var $for = (source, render, keyFn) => {
const marker = document.createComment("sigpro-for"); const marker = document.createComment("sigpro-for-end");
let cache = new Map; let cache = new Map;
$watch(() => { $watch(() => {
const items = (typeof source === "function" ? source() : source) || []; const items = (typeof source === "function" ? source() : source) || [];
const newCache = new Map;
const parent = marker.parentNode; const parent = marker.parentNode;
if (!parent) if (!parent)
return; return;
const newOrder = items.map((item, i) => { const newCache = new Map;
const newOrder = [];
for (let i = 0;i < items.length; i++) {
const item = items[i];
const key = keyFn ? keyFn(item, i) : i; const key = keyFn ? keyFn(item, i) : i;
let cached = cache.get(key); let cached = cache.get(key);
if (!cached) { if (!cached) {
const view = _view(() => render(item, i)); const view = _view(() => render(item, i));
const node = view.container.firstChild || document.createTextNode(""); const node = view.container.firstElementChild || view.container.firstChild;
cached = { node, destroy: view.destroy }; cached = { node, destroy: view.destroy };
} else { } else {
cache.delete(key); cache.delete(key);
} }
newCache.set(key, cached); newCache.set(key, cached);
return cached; newOrder.push(cached.node);
}); }
cache.forEach((c) => { cache.forEach((c) => {
c.destroy(); c.destroy();
c.node.remove(); c.node.remove();
}); });
let anchor = marker; let currentAnchor = marker;
for (let i = newOrder.length - 1;i >= 0; i--) { for (let i = newOrder.length - 1;i >= 0; i--) {
const { node } = newOrder[i]; const node = newOrder[i];
if (node.nextSibling !== anchor) { if (node.nextSibling !== currentAnchor) {
parent.insertBefore(node, anchor); parent.insertBefore(node, currentAnchor);
} }
anchor = node; currentAnchor = node;
} }
cache = newCache; cache = newCache;
}); });

2
dist/sigpro.min.js vendored

File diff suppressed because one or more lines are too long

View File

@@ -252,19 +252,21 @@ const $html = (tag, props = {}, content = []) => {
const append = (child) => { const append = (child) => {
if (Array.isArray(child)) return child.forEach(append); if (Array.isArray(child)) return child.forEach(append);
if (typeof child === "function") { if (child instanceof Node) {
el.appendChild(child);
} else if (typeof child === "function") {
const marker = document.createTextNode(""); const marker = document.createTextNode("");
el.appendChild(marker); el.appendChild(marker);
let nodes = []; let nodes = [];
el._cleanups.add($watch(() => { el._cleanups.add($watch(() => {
const result = child(), nextNodes = (Array.isArray(result) ? result : [result]).map((item) => const res = child(), next = (Array.isArray(res) ? res : [res]).map((i) =>
item?._isRuntime ? item.container : item instanceof Node ? item : document.createTextNode(item ?? "") i?._isRuntime ? i.container : i instanceof Node ? i : document.createTextNode(i ?? "")
); );
nodes.forEach((node) => { sweep(node); node.remove(); }); nodes.forEach((n) => { sweep(n); n.remove(); });
nextNodes.forEach((node) => marker.parentNode?.insertBefore(node, marker)); next.forEach((n) => marker.parentNode?.insertBefore(n, marker));
nodes = nextNodes; nodes = next;
})); }));
} else el.appendChild(child instanceof Node ? child : document.createTextNode(child ?? "")); } else el.appendChild(document.createTextNode(child ?? ""));
}; };
append(content); append(content);
return el; return el;
@@ -307,43 +309,45 @@ $if.not = (condition, thenVal, otherwiseVal) => $if(() => !(typeof condition ===
* @returns {HTMLElement} A reactive container (display: contents). * @returns {HTMLElement} A reactive container (display: contents).
*/ */
const $for = (source, render, keyFn) => { const $for = (source, render, keyFn) => {
const marker = document.createComment("sigpro-for"); const marker = document.createComment("sigpro-for-end");
let cache = new Map(); let cache = new Map();
$watch(() => { $watch(() => {
const items = (typeof source === "function" ? source() : source) || []; const items = (typeof source === "function" ? source() : source) || [];
const newCache = new Map();
const parent = marker.parentNode; const parent = marker.parentNode;
if (!parent) return; if (!parent) return;
const newOrder = items.map((item, i) => { const newCache = new Map();
const newOrder = [];
for (let i = 0; i < items.length; i++) {
const item = items[i];
const key = keyFn ? keyFn(item, i) : i; const key = keyFn ? keyFn(item, i) : i;
let cached = cache.get(key); let cached = cache.get(key);
if (!cached) { if (!cached) {
const view = _view(() => render(item, i)); const view = _view(() => render(item, i));
const node = view.container.firstChild || document.createTextNode(""); const node = view.container.firstElementChild || view.container.firstChild;
cached = { node, destroy: view.destroy }; cached = { node, destroy: view.destroy };
} else { } else {
cache.delete(key); cache.delete(key);
} }
newCache.set(key, cached); newCache.set(key, cached);
return cached; newOrder.push(cached.node);
}); }
cache.forEach(c => { cache.forEach(c => {
c.destroy(); c.destroy();
c.node.remove(); c.node.remove();
}); });
let anchor = marker; let currentAnchor = marker;
for (let i = newOrder.length - 1; i >= 0; i--) { for (let i = newOrder.length - 1; i >= 0; i--) {
const { node } = newOrder[i]; const node = newOrder[i];
if (node.nextSibling !== anchor) { if (node.nextSibling !== currentAnchor) {
parent.insertBefore(node, anchor); parent.insertBefore(node, currentAnchor);
} }
anchor = node; currentAnchor = node;
} }
cache = newCache; cache = newCache;