Proč webové komponenty zaostávají ve výkonu a vývojářském pohodlí
Webové komponenty, jako jsou Lit a Symbiote, vytvářejí každý prvek jako HTMLElement, což vede k alokaci přibližně 124 bajtů na C++ heap. To je 8krát více než 16 bajtů pro JS-objekt v $mol. Pro 1000 úkolů spotřebují Lit/Symbiote přibližně 124 KB pouze na DOM uzly, zatímco $mol pouze přibližně 16 KB. Při 10 000 úkolech rozdíl dosahuje 1,2 MB oproti 160 KB.
Bez virtualizace začne rozhraní s tisíci prvky zpožďovat. Specifikace Custom Elements vyžaduje dědění od HTMLElement, což nevyhnutelně vytváří DOM uzel i pro neviditelné prvky.
// Lit: každý todo-item je HTMLElement (C++ heap, ~124 bajtů minimum)
@customElement("todo-item")
export class TodoItem extends LitElement { ... }
// <todo-item> okamžitě alokuje DOM uzel při createElement
// Symbiote: podobně, každý <todo-item> = HTMLElement
class TodoItem extends Symbiote { ... }
TodoItem.reg('todo-item');
// $mol: komponenta je JS-objekt. DOM se vytváří POUZE při renderování.
// 1000 úkolů v modelu ≠ 1000 DOM prvků
// $mol renderuje pouze viditelné komponenty (virtualizace)
task_rows() {
return this.task_ids_filtered().map(id => this.Task_row(id))
}
Autor SolidJS potvrzuje: pro maximální výkon nejsou webové komponenty vhodné, protože minimalizace DOM uzlů není možná.
Ztráty v rychlosti kvůli DOM operacím
DOM operace jsou mnohonásobně pomalejší než JS vlastnosti kvůli C++ vazbám a absenci JIT optimalizace:
| Operace | Čas | Kolikrát horší |
|---------------------------|------------|----------------|
| obj.title = x (JS) | 1–2 ns | 1x |
| element.textContent = x | 30–60 ns | 30x |
| element.setAttribute | 50–100 ns | 50x |
| element.style.color = x | 80–150 ns | 80x |
Při hromadné aktualizaci (např. označení všech úkolů v TodoMVC) se výkon zhoršuje:
| Úkolů | Lit | $mol | Rozdíl |
|---------|-----------|---------|--------|
| 100 | 60 µs | 3 µs | 20x |
| 1 000 | 600 µs | 8 µs | 75x |
| 10 000 | 8 ms | 12 µs | 650x |
| 100 000 | 120 ms | 15 µs | 8000x |
// Lit: aktualizace přes DOM property
render() {
return html`<label> ${this.text} </label>`;
// Lit v pozadí provádí: node.textContent = value
}
// $mol: aktualizace přes JS property
// this.title() — čtení z memo-cache (JS heap)
// DOM se aktualizuje dávkově přes requestAnimationFrame
task_title(id, next?) {
return this.task(id, ...)!.title ?? ''
}
Parsování HTML v Lit přidává režii.
Rozdíly v reaktivitě
Webové komponenty používají push sémantiku: události se rozesílají všem odběratelům při jakékoli změně.
// Lit: Push přes EventTarget + requestUpdate
export class Todos extends EventTarget {
#notifyChange() {
this.dispatchEvent(new Event("change")); // push!
}
add(text) {
this.#todos.push({ ... });
this.#notifyChange(); // ← ruční push
}
}
// Každá komponenta se přihlašuje přes @updateOnEvent("change")
// Při JAKÉKOLI změně VŠICHNI odběratelé dostanou oznámení
// $mol: Pull — automatický graf závislostí
@$mol_mem
groups_completed() {
// Automaticky sleduje závislosti:
// task_ids() → task() → groups
// Přepočítává se POUZE když se změnily závislosti
for (let id of this.task_ids()) {
var task = this.task(id)!;
groups[String(task.completed)].push(id);
}
return groups;
}
// Není potřeba ani EventTarget, ani ruční odběry
Pull reaktivita ($mol, Vue) minimalizuje zbytečné aktualizace a snižuje objem kódu. Push zvyšuje riziko chyb v odběrech.
Testování a dědění
Testování webových komponent vyžaduje DOM: vytváření prvků, connectedCallback, čekání na updateComplete. V $mol testy pracují s JS-objekty bez DOM.
// $mol: testy BEZ DOM
'task add'($) {
const app = $hyoo_todomvc.make({ $ })
app.Add().value('test')
app.Add().submit()
$mol_assert_equal(app.task_rows().at(-1)!.title(), 'test')
}
Dědění v Lit vyžaduje kopírování celého render()-bloku:
class MyTodoApp extends TodoApp {
render() {
// Kopírujeme 40+ řádků HTML, měníme pouze footer
}
}
V $mol dědění nahrazuje pouze potřebné sub-prvky:
$my_custom_todo $hyoo_todomvc
foot <= My_footer $mol_view
// Vše ostatní se dědí
Co je důležité
- Webové komponenty spotřebují přibližně 124 bajtů/prvek na DOM, což je kritické pro seznamy.
- DOM operace jsou 30–80krát pomalejší než JS vlastnosti, degradace při škálování.
- Push reaktivita vyžaduje ruční odběry, pull je jednodušší a efektivnější.
- Testy webových komponent jsou pomalé kvůli DOM, $mol testuje čisté objekty.
- Dědění ve webových komponentách vede ke kopírování šablon.
— Editorial Team
Zatím žádné komentáře.