Zpět na domů

Problémy webových komponent: výkon a API

Článek analyzuje klíčové problémy webových komponent: nadměrný boilerplate pro vlastnosti, nízký výkon kvůli host-proxy, globální registraci s konflikty a nepohodlí Shadow DOM. Uvádějí se benchmarky a příklady kódu.

Proč webové komponenty zpomalují: benchmarky a kód
Advertisement 728x90

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:

Google AdInline article slot
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:

Google AdInline article slot
  • 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.

Google AdInline article slot

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

Advertisement 728x90

Číst dál