1
0
mirror of https://github.com/jaandrle/deka-dom-el synced 2025-07-29 07:00:16 +02:00

🔤 T now uses DocumentFragment

This commit is contained in:
2025-03-13 12:58:38 +01:00
parent 25d475ec04
commit 0a2d17ac6f
14 changed files with 330 additions and 328 deletions

View File

@@ -45,7 +45,7 @@ const references= {
export function page({ pkg, info }){
const page_id= info.id;
return el(simplePage, { info, pkg }).append(
el("p").append(...T`
el("p").append(T`
As your applications grow, performance becomes increasingly important. dd<el> provides several
techniques to optimize rendering performance, especially when dealing with large lists or frequently
updating components. This guide focuses on memoization and other optimization strategies.
@@ -63,7 +63,7 @@ export function page({ pkg, info }){
el(code, { src: fileURL("./components/examples/optimization/intro.js"), page_id }),
el(h3, t`Memoization with memo: Native vs dd<el>`),
el("p").append(...T`
el("p").append(T`
In standard JavaScript applications, optimizing list rendering often involves manual caching
or relying on complex virtual DOM diffing algorithms. dd<el>'s ${el("code", "memo")} function
provides a simpler, more direct approach:
@@ -106,13 +106,13 @@ export function page({ pkg, info }){
)
)
),
el("p").append(...T`
el("p").append(T`
The ${el("a", references.memo_docs).append(el("code", "memo"))} function in dd<el> allows you to
cache and reuse DOM elements instead of recreating them on every render, which can
significantly improve performance for components that render frequently or contain heavy computations.
`),
el("p").append(...T`
el("p").append(T`
The memo system is particularly useful for:
`),
el("ul").append(
@@ -122,7 +122,7 @@ export function page({ pkg, info }){
),
el(h3, t`Using memo with Signal Rendering`),
el("p").append(...T`
el("p").append(T`
The most common use case for memoization is within ${el("code", "S.el()")} when rendering lists with
${el("code", "map()")}:
`),
@@ -136,7 +136,7 @@ export function page({ pkg, info }){
))))
`, page_id }),
el("p").append(...T`
el("p").append(T`
The ${el("code", "memo")} function in this context:
`),
el("ol").append(
@@ -149,7 +149,7 @@ export function page({ pkg, info }){
el(example, { src: fileURL("./components/examples/optimization/memo.js"), page_id }),
el(h3, t`Creating Memoization Scopes`),
el("p").append(...T`
el("p").append(T`
The ${el("code", "memo()")} uses cache store defined via the ${el("code", "memo.scope")} function.
That is actually what the ${el("code", "S.el")} is doing under the hood:
`),
@@ -173,7 +173,7 @@ export function page({ pkg, info }){
);
`, page_id }),
el("p").append(...T`
el("p").append(T`
The scope function accepts options to customize its behavior:
`),
el(code, { content: `
@@ -193,12 +193,12 @@ export function page({ pkg, info }){
el("div", { className: "function-table" }).append(
el("dl").append(
el("dt", t`onlyLast Option`),
el("dd").append(...T`Only keeps the cache from the most recent function call,
el("dd").append(T`Only keeps the cache from the most recent function call,
which is useful when the entire collection is replaced. ${el("strong", "This is default behavior of ")
.append(el("code", "S.el"))}!`),
el("dt", t`signal Option`),
el("dd").append(...T`An ${el("a", references.mdn_abort).append(el("code", "AbortSignal"))}
el("dd").append(T`An ${el("a", references.mdn_abort).append(el("code", "AbortSignal"))}
that will clear the cache when aborted, helping with memory management`)
)
),
@@ -206,7 +206,7 @@ export function page({ pkg, info }){
el(h3, t`Additional Optimization Techniques`),
el("h4", t`Minimizing Signal Updates`),
el("p").append(...T`
el("p").append(T`
Signals are efficient, but unnecessary updates can impact performance:
`),
el("ul").append(
@@ -217,7 +217,7 @@ export function page({ pkg, info }){
),
el("h4", t`Optimizing List Rendering`),
el("p").append(...T`
el("p").append(T`
Beyond memoization, consider these approaches for optimizing list rendering:
`),
el("ul").append(
@@ -228,17 +228,17 @@ export function page({ pkg, info }){
),
el("div", { className: "tip" }).append(
el("p").append(...T`
el("p").append(T`
Memoization works best when your keys are stable and unique. Use IDs or other persistent
identifiers rather than array indices, which can change when items are reordered.
`),
el("p").append(...T`
el("p").append(T`
Alternatively you can use any “jsonable” value as key, when the primitive values arent enough.
`)
),
el("h4", t`Memory Management`),
el("p").append(...T`
el("p").append(T`
To prevent memory leaks and reduce memory consumption:
`),
el("ul").append(
@@ -249,7 +249,7 @@ export function page({ pkg, info }){
),
el("h4", t`Choosing the Right Optimization Approach`),
el("p").append(...T`
el("p").append(T`
While memo is powerful, it's not always the best solution:
`),
el("table").append(
@@ -280,12 +280,12 @@ export function page({ pkg, info }){
),
el(h3, t`Known Issues and Limitations`),
el("p").append(...T`
el("p").append(T`
While memoization is a powerful optimization technique, there are some limitations and edge cases to be aware of:
`),
el("h4", t`Document Fragments and Memoization`),
el("p").append(...T`
el("p").append(T`
One important limitation to understand is how memoization interacts with
${el("a", references.mdn_fragment).append("DocumentFragment")} objects.
Functions like ${el("code", "S.el")} internally use DocumentFragment to efficiently handle multiple elements,
@@ -305,7 +305,7 @@ export function page({ pkg, info }){
container.append(memoizedFragment); // Nothing gets appended
`, page_id }),
el("p").append(...T`
el("p").append(T`
This happens because a DocumentFragment is emptied when it's appended to the DOM. When the fragment
is cached by memo and reused, it's already empty.
`),
@@ -327,7 +327,7 @@ export function page({ pkg, info }){
`, page_id })
),
el("p").append(...T`
el("p").append(T`
Generally, you should either:
`),
el("ol").append(
@@ -337,7 +337,7 @@ export function page({ pkg, info }){
),
el("div", { className: "note" }).append(
el("p").append(...T`
el("p").append(T`
This limitation isn't specific to dd<el> but is related to how DocumentFragment works in the DOM.
Once a fragment is appended to the DOM, its child nodes are moved from the fragment to the target element,
leaving the original fragment empty.
@@ -345,11 +345,11 @@ export function page({ pkg, info }){
),
el(h3, t`Performance Debugging`),
el("p").append(...T`
el("p").append(T`
To identify performance bottlenecks in your dd<el> applications:
`),
el("ol").append(
el("li").append(...T`Use ${el("a", references.mdn_perf).append("browser performance tools")} to profile
el("li").append(T`Use ${el("a", references.mdn_perf).append("browser performance tools")} to profile
rendering times`),
el("li", t`Check for excessive signal updates using S.on() listeners with console.log`),
el("li", t`Verify memo usage by inspecting cache hit rates`),
@@ -357,26 +357,26 @@ export function page({ pkg, info }){
),
el("div", { className: "note" }).append(
el("p").append(...T`
el("p").append(T`
For more details on debugging, see the ${el("a", { href: "p07-debugging.html", textContent: "Debugging" })} page.
`)
),
el(h3, t`Best Practices for Optimized Rendering`),
el("ol").append(
el("li").append(...T`
el("li").append(T`
${el("strong", "Use memo for list items:")} Memoize items in lists, especially when they contain complex components.
`),
el("li").append(...T`
el("li").append(T`
${el("strong", "Clean up with AbortSignals:")} Connect memo caches to component lifecycles using AbortSignals.
`),
el("li").append(...T`
el("li").append(T`
${el("strong", "Profile before optimizing:")} Identify actual bottlenecks before adding optimization.
`),
el("li").append(...T`
el("li").append(T`
${el("strong", "Use derived signals:")} Compute derived values efficiently with signal computations.
`),
el("li").append(...T`
el("li").append(T`
${el("strong", "Avoid memoizing fragments:")} Memoize individual elements or use container elements
instead of DocumentFragments.
`)