Problémy s výkonem a API webových komponent
Vytvoření webového komponentu s jedním vlastností vyžaduje značné množství kódu prostřednictvím Custom Elements API. Základní implementace je omezena řetězcovými atributy, což vyžaduje serializaci pro ostatní datové typy.
Příklad minimálního komponentu:
class MyFoo extends HTMLElement {
_bar = 0
get bar() {
return this._bar
}
set bar( next ) {
this.setAttribute( 'bar', next )
}
static observedAttributes = [ 'bar' ]
attributeChangedCallback( name, prev, next ) {
this[ '_' + name ] = next
}
}
globalThis.customElements.define( 'my-foo', MyFoo )
Pro podporu čísel se přidává JSON-serializace s příznakem _muted_, který zabrání rekurzi:
class MyFoo extends HTMLElement {
_bar = 0
get bar() {
return this._bar
}
set bar( next ) {
this._bar = next
this._muted_ = true; try {
this.setAttribute( 'bar', JSON.stringify( next ) )
} finally { this._muted_ = false }
}
_muted_ = false
static observedAttributes = [ 'bar' ]
attributeChangedCallback( name, prev, next ) {
if( this._muted_ ) return
this[ '_' + name ] = JSON.parse( next )
}
}
To vede k problémům s únikem řetězců v atribucích a vyžaduje další vrstvy abstrakce pro data, objekty a jiné typy.
Výkon: mikrosekundy zabíjejí snímky
Webové komponenty jsou o řád pomalejší než běžné JS objekty kvůli proxy přes runtime hostitele. Srovnání času vytvoření:
- Běžný JS objekt: ~0,01 μs
- Webový komponent: ~1–3 μs
Tisíce komponent zabere 1–3 ms na vytvoření, což spotřebovává významnou část 16 ms snímku. Změna vlastnosti také vyžaduje mikrosekundy:
- Jednoduché přiřazení v JS: nanosekundy
- Setter webového komponentu: mikrosekundy
Příčina – trvalý přenos dat mezi JS a C++ runtime prohlížeče, což blokuje JIT inline. Paměť: 124 bajtů na jednoduchý webový komponent proti 16 bajtům u JS objektu.
Globální registrace a konflikty
Registrace komponent je globální a nevrací se až do zavření kartu:
customElements.define( 'ya-button', YandexButton )
// ...
customElements.define( 'ya-button', YahooButton ) // 💥 Chyba: název již použit
Konflikty jmen narušují modulárnost. CustomElementRegistry ve Shadow DOM řeší problém částečně, ale polyfilly nejsou dostupné a sloučení registru vyžaduje jmenný prostor.
Alternativy:
- Globální fraktální registr, jako DNS
- VerLess – aktualizace bez porušení kompatibility
Životní cyklus a Shadow DOM
connectedCallback/disconnectedCallback se spouští při jakémkoli přesunu komponenty, včetně přesunu na stejné místo, což způsobuje kaskádu v podstromu. To vede ke zbytečným asynchronním úlohám.
Shadow DOM poskytuje izolaci, ale komplikuje stylizaci: adoptedStyleSheets vyžadují dynamický import stylů zvenčí. Názvy prvků jsou striktně ve formátu kebab-case, což konfliktuje se standardními DOM prvky.
Co je důležité
- Výkon: webové komponenty jsou 100–1000× pomalejší než JS objekty kvůli hostitelskému proxy
- Boilerplate: serializace/deserializace je nutná pro neřetězcové vlastnosti
- Registrace: globální, nevrací se, s konflikty jmen
- Životní cyklus: hooky se spouští při přesunech, způsobují kaskády
- Shadow DOM: komplikuje přizpůsobení stylů a polyfilling
Webové komponenty nepodporují statickou typizaci TypeScript ani reaktivitu z krabice, což vyžaduje frameworky pro skutečné aplikace.
— Editorial Team
Zatím žádné komentáře.