Ultra Optimice $for

This commit is contained in:
2026-04-03 19:19:20 +02:00
parent c0300e20d3
commit 29c6451706
4 changed files with 45 additions and 43 deletions

40
dist/sigpro.js vendored
View File

@@ -317,40 +317,42 @@
}; };
$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.createTextNode(""); const marker = document.createComment("sigpro-for");
const container = $html("div", { style: "display:contents" }, [marker]);
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 newCache = new Map;
const newOrder = []; const parent = marker.parentNode;
for (let i = 0;i < items.length; i++) { if (!parent)
const item = items[i]; return;
const newOrder = items.map((item, i) => {
const key = keyFn ? keyFn(item, i) : i; const key = keyFn ? keyFn(item, i) : i;
let run = cache.get(key); let cached = cache.get(key);
if (!run) { if (!cached) {
run = _view(() => render(item, i)); const view = _view(() => render(item, i));
const node = view.container.firstChild || document.createTextNode("");
cached = { node, destroy: view.destroy };
} else { } else {
cache.delete(key); cache.delete(key);
} }
newCache.set(key, run); newCache.set(key, cached);
newOrder.push(key); return cached;
} });
cache.forEach((run) => { cache.forEach((c) => {
run.destroy(); c.destroy();
run.container.remove(); c.node.remove();
}); });
let anchor = marker; let anchor = marker;
for (let i = newOrder.length - 1;i >= 0; i--) { for (let i = newOrder.length - 1;i >= 0; i--) {
const run = newCache.get(newOrder[i]); const { node } = newOrder[i];
if (run.container.nextSibling !== anchor) { if (node.nextSibling !== anchor) {
container.insertBefore(run.container, anchor); parent.insertBefore(node, anchor);
} }
anchor = run.container; anchor = node;
} }
cache = newCache; cache = newCache;
}); });
return container; return marker;
}; };
var $router = (routes) => { var $router = (routes) => {
const sPath = $(window.location.hash.replace(/^#/, "") || "/"); const sPath = $(window.location.hash.replace(/^#/, "") || "/");

2
dist/sigpro.min.js vendored

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,6 @@
{ {
"name": "sigpro", "name": "sigpro",
"version": "1.1.18", "version": "1.1.19",
"type": "module", "type": "module",
"license": "MIT", "license": "MIT",
"main": "./index.js", "main": "./index.js",

View File

@@ -306,50 +306,50 @@ $if.not = (condition, thenVal, otherwiseVal) => $if(() => !(typeof condition ===
* @param {Function} keyFn - Function to extract a unique key from the item. * @param {Function} keyFn - Function to extract a unique key from the item.
* @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.createTextNode(""); const marker = document.createComment("sigpro-for");
const container = $html("div", { style: "display:contents" }, [marker]);
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 newCache = new Map();
const newOrder = []; const parent = marker.parentNode;
for (let i = 0; i < items.length; i++) { if (!parent) return;
const item = items[i];
const newOrder = items.map((item, i) => {
const key = keyFn ? keyFn(item, i) : i; const key = keyFn ? keyFn(item, i) : i;
let cached = cache.get(key);
let run = cache.get(key); if (!cached) {
if (!run) { const view = _view(() => render(item, i));
run = _view(() => render(item, i)); const node = view.container.firstChild || document.createTextNode("");
cached = { node, destroy: view.destroy };
} else { } else {
cache.delete(key); cache.delete(key);
} }
newCache.set(key, cached);
return cached;
});
newCache.set(key, run); cache.forEach(c => {
newOrder.push(key); c.destroy();
} c.node.remove();
cache.forEach(run => {
run.destroy();
run.container.remove();
}); });
let anchor = marker; let anchor = marker;
for (let i = newOrder.length - 1; i >= 0; i--) { for (let i = newOrder.length - 1; i >= 0; i--) {
const run = newCache.get(newOrder[i]); const { node } = newOrder[i];
if (run.container.nextSibling !== anchor) { if (node.nextSibling !== anchor) {
container.insertBefore(run.container, anchor); parent.insertBefore(node, anchor);
} }
anchor = run.container; anchor = node;
} }
cache = newCache; cache = newCache;
}); });
return container; return marker;
}; };
/** /**