Opublikowano: 19 maja 2026 r.
Internet już dawno przestał być statycznym medium opartym na dokumentach, jakim był na początku. Nowoczesne, zaawansowane aplikacje internetowe są używane przez wszystkich z wielu powodów – od komunikacji, zakupów i korzystania ze szczegółowych treści po zarządzanie złożonym życiem.
HTML, pomimo wszystkich swoich zalet, nadal jest dostarczany w kolejności od góry do dołu, bez względu na to, kiedy treść jest gotowa lub kiedy użytkownik ją konsumuje. CSS umożliwia zmianę kolejności treści, ale często wiąże się to z poważnymi skutkami ubocznymi w zakresie dostępności. JavaScript umożliwia manipulowanie modelem DOM za pomocą różnych interfejsów API, co pozwala częściowo obejść to ograniczenie, ale często wymaga to rozbudowanej składni lub tworzenia drzew DOM, które można podłączyć do HTML.
Skuteczność jest niezwykle ważna w przypadku internetu ze względu na charakter klienta i serwera, ale często podejmuje się nieoptymalne decyzje, aby obejść kolejność HTML, co spowalnia działanie. Może to obejmować czekanie, aż cała strona będzie gotowa, lub używanie rozbudowanego frameworka do dostarczania komponentów w sposób asynchroniczny. Popularność frameworków JavaScriptu pokazuje, że programiści wolą model oparty na komponentach od sztywnego modelu dokumentu, który był podstawą internetu w jego początkach.
Zespół Chrome rozważał ten problem i opracował nowe dodatki do platformy internetowej pod nazwą Deklaratywne aktualizacje częściowe.
Dwa nowe zestawy interfejsów API ułatwiają dostarczanie kodu HTML w mniej liniowy sposób, zarówno w przypadku kolejności w dokumencie HTML, jak i w przypadku łatwiejszych sposobów dynamicznego wstawiania kodu HTML do istniejących dokumentów za pomocą nowych interfejsów API JavaScript. Są one gotowe do testowania przez deweloperów w Chrome 148 przy użyciu flagi chrome://flags/#enable-experimental-web-platform-features. Dostępne są też polyfille, które umożliwiają natychmiastowe korzystanie z tych nowych interfejsów API, nawet w przeglądarkach, które jeszcze ich nie obsługują.
Te dodatki do platformy internetowej są standaryzowane przy pozytywnych opiniach innych dostawców przeglądarek i ścieżek standaryzacji. Odpowiednie standardy są w trakcie aktualizacji, aby uwzględnić te nowe interfejsy API.
Strumieniowanie poza kolejnością
Pierwszy zestaw zmian to nowe interfejsy API do przesyłania strumieniowego w nieodpowiedniej kolejności, które używają elementu HTML <template> i symboli zastępczych instrukcji przetwarzania. Na przykład:
<div>
<?marker name="placeholder">
</div>
...
<template for="placeholder">
Here is some <em>HTML content</em>!
</template>
Instrukcje przetwarzania istnieją w XML od dawna, ale w HTML są traktowane jako komentarze i ignorowane. Ten nowy interfejs API zmienia to i wprowadza instrukcje przetwarzania do HTML. Gdy przeglądarka zobaczy instrukcje przetwarzania <?marker name="placeholder">, nie podejmuje od razu żadnych działań – podobnie jak wcześniej – ale można się do nich odwołać później.
Element <template> wyszukuje odpowiednie instrukcje przetwarzania za pomocą atrybutu name i zastępuje nimi treść. W tym przypadku po przeanalizowaniu DOM będzie wyglądać tak:
<div>
Here is some <em>HTML content</em>!
</div>
Oprócz atrybutu <?marker> dla zamienników istnieją też znaczniki zakresu <?start> i <?end>, które umożliwiają wyświetlanie tymczasowych treści zastępczych przed przetworzeniem szablonu:
<div>
<?start name="another-placeholder">
Loading…
<?end>
</div>
...
<template for="another-placeholder">
Here is some <em>HTML content</em>!
</template>
W tym przypadku Loading… wyświetla się do momentu, gdy pojawi się <template>, a następnie zostaje zastąpiony nową treścią.
W szablonach można też umieszczać instrukcje przetwarzania, aby umożliwić wiele aktualizacji:
<ul id="results">
<?start name="results">
Loading…
<?end>
</ul>
...
<template for="results">
<li>Result One</li>
<?marker name="results">
</template>
...
<template for="results">
<li>Result Two</li>
<?marker name="results">
</template>
...
Po przetworzeniu daje to taki kod HTML:
<ul id="results">
<li>Result One</li>
<li>Result Two</li>
<?marker name="results">
</ul>
Z końcową instrukcją przetwarzania na końcu, na wypadek gdyby do dokumentu dodano później więcej <template for="results">.
Prezentacja
W tym filmie pokazujemy, jak zaimplementować podstawową aplikację do albumu ze zdjęciami za pomocą strumieniowego HTML:
Zarówno stan, jak i zdjęcia są przesyłane strumieniowo do kodu HTML po początkowym układzie.
Przypadki użycia
Istnieje wiele przypadków użycia tego kodu HTML do aktualizacji poza kolejnością w połączeniu ze strumieniowaniem HTML:
- Architektura wyspowa Popularny wzorzec spopularyzowany przez platformy takie jak Astro to architektura wysp, w której komponenty są renderowane niezależnie na statycznym kodzie HTML. Interfejs
<template for>API umożliwia obsługę treści statycznych w podobny sposób bezpośrednio w HTML. Frameworki JavaScriptu mogą też używać tego do tworzenia bardziej interaktywnych wysp lub obsługi komponentów. - Dostarczaj treści, gdy są gotowe. Dzięki tej architekturze wysp treści mogą być przesyłane strumieniowo, gdy są gotowe, zamiast być wstrzymywane z powodu treści wymagających dodatkowego przetwarzania, np. wyszukiwania w bazie danych. Wiele platform umożliwia przesyłanie strumieniowe HTML, ale ze względu na kolejność elementów HTML treść jest często opóźniana lub wymaga złożonych manipulacji DOM w JavaScript. Teraz możesz dostarczać statyczne treści w trakcie oczekiwania, a następnie na końcu strumienia HTML umieszczać treści wymagające większych nakładów.
- Kod HTML może być dostarczany w optymalnej kolejności, co zwiększa wydajność wczytywania strony. Możesz zmienić kolejność nawet wtedy, gdy jest już gotowa. Przykładem są mega menu, które są popularną funkcją nawigacyjną zawierającą dużo kodu HTML, który użytkownik zobaczy dopiero wtedy, gdy strona stanie się interaktywna. Ten duży fragment kodu HTML może być dostarczany później w dokumencie HTML, aby nadać priorytet ważniejszemu kodowi HTML potrzebnemu do początkowego wczytania strony. Kolejność nie jest już problemem w przypadku HTML.
To tylko niektóre przypadki użycia. Z niecierpliwością czekamy na to, do czego deweloperzy wykorzystają ten nowy interfejs API.
Ograniczenia i subtelności
Interfejs API ma kilka ograniczeń i subtelności, o których warto pamiętać:
- Ze względów bezpieczeństwa
<template for>może aktualizować instrukcje przetwarzania tylko w ramach tego samego elementu nadrzędnego. Dodanie elementu<template for>bezpośrednio do elementu<body>daje mu dostęp do całego dokumentu (w tym do elementu<head>). - Instrukcja przetwarzania
<?end>jest opcjonalna. Jeśli jej brakuje, zawartość między elementem<?start>a końcem elementu zawierającego zostanie zastąpiona. - Przeniesienie instrukcji przetwarzania po rozpoczęciu przesyłania strumieniowego
<template for>może mieć nieoczekiwane konsekwencje, ponieważ nowe treści będą nadal przesyłane strumieniowo do starej lokalizacji. - Pamiętaj, że podczas dynamicznego wstawiania
<template for>za pomocą metody takiej jaksetHTMLlubinnerHTML„elementem nadrzędnym” szablonu podczas jego analizowania jest pośredni fragment dokumentu. Oznacza to, że wstawianie kodu HTML za pomocą tych metod nie może modyfikować istniejącego DOM, a zmiany są wprowadzane „w miejscu” w fragmencie. Jednak w przypadku strumieniowania za pomocą metod takich jakstreamHTMLUnsafe(o których za chwilę opowiemy) nie ma fragmentu pośredniego, więc szablony mogą zastępować istniejące treści.
Potencjalne dodatki w przyszłości
Rozważamy dodanie w przyszłości m.in. tych funkcji:
- Obejmuje komponenty po stronie klienta. Na przykład:
<template for="footer" patchsrc="/partials/footer.html">. - Grupowanie Po stronie klienta można też rozszerzyć fragmenty, aby obsługiwały przetwarzanie wsadowe, co zapewni jednoczesne wprowadzanie wielu aktualizacji.
- Zapobieganie zastępowaniu treści, które się nie zmienią. Można to osiągnąć za pomocą numeru wersji treści lub obsługi wersji. Dzięki temu stan będzie zachowywany między zmianami trasy lub innymi aktualizacjami, zamiast resetować zawartość.
- Dezynfekcja podczas łatania. Na przykład
<template for=icon safe><svg id="from-untrusted-source">...</svg></template>
Kod polyfill
Zespół Chrome udostępnił template-for-polyfill, który jest dostępny w npm, aby umożliwić witrynom natychmiastowe korzystanie z tej nowej funkcji, jeszcze zanim pojawi się ona w innych przeglądarkach.
Istnieją pewne ograniczenia, ponieważ nie można bezpośrednio aktualizować parserów HTML przeglądarki, ale najczęstsze przypadki użycia są obsługiwane. Witryny powinny być nadal testowane w innych przeglądarkach.
Odnowione metody wstawiania kodu HTML i przesyłania strumieniowego
Nie wszystkie treści można dostarczyć w formacie HTML. Drugi aspekt pracy Chrome w tym obszarze polega na ułatwieniu aktualizowania treści za pomocą JavaScriptu.
Istnieje już kilka sposobów na dynamiczne wstrzykiwanie kodu HTML do istniejącego dokumentu za pomocą JavaScriptu:
setHTMLsetHTMLUnsafeinnerHTMLiouterHTMLcreateContextualFragmentinsertAdjacentHTML
Wszystkie działają jednak nieco inaczej, a programiści nie zawsze biorą pod uwagę subtelności i różnice:
- Czy nowe treści zastępują poprzednie, czy są do nich dołączane?
- Czy oczyszczają potencjalnie niebezpieczny kod HTML, np. przez zastępowanie tagów
<script>? - Jeśli nie, czy
<script>powinien działać? - Jak działają w przypadku Trusted Types?
Niewielu deweloperów mogło szczerze przyjrzeć się tym interfejsom API i z pewnością odpowiedzieć na te pytania w przypadku każdego z nich.
Dużym ograniczeniem jest to, że można ich używać tylko w przypadku pełnego zestawu HTML znanego z wyprzedzeniem, podczas gdy pojawiały się prośby o umożliwienie strumieniowania HTML. W praktyce oznacza to, że przed wstawieniem treści musisz pobrać je w całości, podczas gdy jedną z największych zalet HTML jest możliwość natychmiastowego przesyłania strumieniowego treści. Można to w ograniczonym stopniu obejść, dzieląc ładunki lub używając nieaktualnych metod, takich jak document.write, ale wiąże się to z własnymi problemami.
Nowy zestaw interfejsów API do statycznego i strumieniowego przesyłania danych
Chrome zaproponował zestaw nowych interfejsów API i rozszerzeń do istniejących setHTML i setHTMLUnsafe, które upraszczają ten proces, a także wprowadzają funkcję przesyłania strumieniowego:
Istnieją metody ustawiania lub zastępowania, a także metody wstawiania treści przed lub po istniejącym kodzie HTML. Każda metoda ma odpowiedniki w strumieniu:
| Działanie | Statyczny | Streaming |
|---|---|---|
| Ustawianie zawartości HTML elementu | setHTML(html, options); |
streamHTML(options); |
| Zastąp cały element tym kodem HTML | replaceWithHTML(html, options); |
streamReplaceWithHTML(options); |
| Dodaj kod HTML przed elementem | beforeHTML(html, options); |
streamBeforeHTML(options); |
| Dodaj kod HTML jako pierwszy element podrzędny elementu. | prependHTML(html, options); |
streamPrependHTML(options); |
| Dodaj kod HTML jako ostatni element podrzędny elementu. | appendHTML(html, options); |
streamAppendHTML(options); |
| Dodaj kod HTML po elemencie | afterHTML(html, options); |
streamAfterHTML(options); |
Istnieją też wersje Unsafe, które omówimy za chwilę. Chociaż może się wydawać, że jest ich dużo (zwłaszcza jeśli dodasz odpowiedniki Unsafe), spójna konwencja nazewnictwa sprawia, że ich działanie jest bardziej oczywiste w porównaniu z niepowiązanymi metodami wspomnianymi wcześniej.
Wersje statyczne przyjmują nowy kod HTML jako argument DOM String wraz z opcjonalnymi opcjami:
const newHTML = "<p>This is a new paragraph</p>";
const contentElement = document.querySelector('#content-to-update');
contentElement.setHTML(newHTML);
Wersje strumieniowe działają z interfejsem Streams API, np. z getWriter():
const contentElement = document.querySelector('#content-to-update');
const writer = contentElement.streamHTMLUnsafe().getWriter();
// Example stream of updating content
while (true) {
await writer.write(`<p>${++i}</p>`);
await new Promise((resolve) => setTimeout(resolve, 1000));
}
writer.close();
Możesz też użyć ciągów potoków w odpowiedzi na pobranie:
const contentElement = document.querySelector('#content-to-update');
const response = await fetch('/api/content.html');
response.body
.pipeThrough(new TextDecoderStream())
.pipeTo(contentElement.streamHTMLUnsafe());
Planujemy też dodać wygodną metodę, która umożliwi bezpośrednie przesyłanie strumieniowe bez konieczności wykonywania pośredniego kroku TextDecoderStream().
Argument options umożliwia określenie niestandardowego sanitizer, którego domyślna wartość to default, czyli domyślna konfiguracja narzędzia do czyszczenia. Używa się jej w ten sposób:
const newHTML = "<p>This is a new paragraph</p>";
const contentElement = document.querySelector('#content-to-update');
// Only allows basic formatting
const basicFormattingSanitzer = new Sanitizer({ elements: ["em", "i", "b", "strong"] });
contentElement.setHTML(newHTML, {sanitizer: basicFormattingSanitzer});
„Niebezpieczne” metody
Istnieją też „niebezpieczne” wersje każdego z interfejsów API:
| Działanie | Statyczny | Streaming |
|---|---|---|
| Ustawianie zawartości HTML elementu | setHTMLUnsafe(html,options); |
streamHTMLUnsafe(options); |
| Zastąp cały element tym kodem HTML | replaceWithHTMLUnsafe(html, options); |
streamReplaceWithHTMLUnsafe(options); |
| Dodaj kod HTML przed elementem | beforeHTMLUnsafe(html, options); |
streamBeforeHTMLUnsafe(options); |
| Dodaj kod HTML jako pierwszy element podrzędny elementu. | prependHTMLUnsafe(html, options); |
streamPrependHTMLUnsafe(options); |
| Dodaj kod HTML jako ostatni element podrzędny elementu. | appendHTMLUnsafe(html, options); |
streamAppendHTMLUnsafe(options); |
| Dodaj kod HTML po elemencie | afterHTMLUnsafe(html, options); |
streamAfterHTMLUnsafe(options); |
Te „niebezpieczne” metody domyślnie wyłączają funkcję oczyszczania (w razie potrzeby możesz określić niestandardową funkcję oczyszczania), a także umożliwiają uruchamianie skryptów z opcjonalną opcją runScripts (która domyślnie ma wartość false).
Podobnie jak setHTML, setHTMLUnsafe to istniejąca metoda, ale dodano do niej parametr opcji runScripts, aby można było jej używać z wykonywaniem skryptu:
const newHTML = `<p>This is a new paragraph</p>
<script src=script.js></script>`;
const contentElement = document.querySelector('#content-to-update');
contentElement.setHTMLUnsafe(newHTML, {runScripts: true});
Słowo „niebezpieczne” w nazwie metody ma przypominać deweloperom o potencjalnym ryzyku i o tym, jak mogą oczyszczać lub ograniczać skrypty, a nie o tym, że nie należy używać tych metod.
To, jak bardzo jest to „niebezpieczne”, zależy od tego, jak bardzo zaufane są dane wejściowe. Wszystkie metody statyczne Unsafe działają zarówno z ciągiem DOM, jak i z obiektem TrustedHTML jako argumentami html, a także umożliwiają używanie narzędzi do oczyszczania. W przypadku runScript chodzi o to, aby zezwolić na skrypty, dlatego domyślnie nie jest używany żaden moduł oczyszczający.
Przypadki użycia
Nowe interfejsy API ułatwiają programistom dodawanie kodu HTML do istniejących stron, a także dodawanie nowych interfejsów API o spójnych nazwach i opcjach. Interfejsy API do przesyłania strumieniowego zapewniają korzyści związane z wydajnością, ponieważ nie musisz czekać, aż cała nowa treść będzie dostępna na platformie.
Przykłady zastosowania:
- Dynamiczne przesyłanie strumieniowe dużych aktualizacji treści w aplikacjach na jednej stronie. Jak wspomnieliśmy wcześniej, dużą wadą obecnych aplikacji SPA jest to, że nie mogą one korzystać ze strumieniowego charakteru początkowych wczytań HTML – aż do teraz.
- Wstawianie typowej treści, np. stopek HTML. Korzystanie z interfejsów JavaScript API umożliwia pobieranie częściowych plików HTML i wstawianie ich na stronę, co pozwala korzystać z pamięci podręcznej zamiast powtarzać je na każdej wysyłanej stronie. Ze względu na zależność od JavaScriptu ta metoda powinna być używana tylko w przypadku treści, które nie będą widoczne podczas początkowego wczytywania.
To tylko kilka przykładów. Nie możemy się doczekać, aż zobaczymy, co wymyślicie.
Ograniczenia i subtelności
Nowe interfejsy API mają też kilka ograniczeń i subtelności, o których warto pamiętać:
- Integracja przesyłania strumieniowego z interfejsem Trusted Types API wymaga użycia nowej metody
createParserOptions, która umożliwia wstrzykiwanie narzędzia do czyszczenia do dowolnej operacji ustawiania HTML. Więcej informacji o integracji zaufanych typów znajdziesz w tym artykule. - Podobnie jak w przypadku
<template for>, przenoszenie elementów strumieniowanych może mieć nieoczekiwane konsekwencje lub powodować błędy strumienia. streamHTMLUnsafedziała pod wieloma względami podobnie do głównego analizatora, w tym przetwarza instrukcje<template for>w miarę ich dodawania do dokumentu głównego i odkłada skryptydeferdo końca strumienia.
Kod polyfill
Zespół Chrome udostępnił html-setters-polyfill, który jest dostępny w npm, aby umożliwić witrynom natychmiastowe korzystanie z tej nowej funkcji, jeszcze zanim pojawi się ona w innych przeglądarkach.
Pamiętaj, że ten kod polyfill nie przesyła strumieniowo, tylko buforuje i stosuje po zakończeniu. Jest to raczej polyfill dla kształtu interfejsu API niż dla funkcjonalności.
Ustawienie bezpiecznych treści zależy też od setHTML i interfejsu Sanitizer API, który nie jest obsługiwany w Safari.
Używaj ich razem
Są to 2 osobne interfejsy API, ale prawdziwa moc tkwi w ich połączeniu. Przesyłając strumieniowo nowe elementy <template for> do kodu HTML, możesz dynamicznie aktualizować różne części treści bez konieczności bezpośredniego kierowania na każdą z nich za pomocą osobnych odwołań JavaScriptu do DOM.
Podstawowe wczytywanie strony w stylu SPA można zrealizować, wczytując stronę z instrukcjami przetwarzania, a następnie przesyłając strumieniowo szablony każdej nowej strony na dół kodu HTML, aby umieścić je w tych instrukcjach.
Oba te interfejsy API mają niewątpliwie większy potencjał i więcej zastosowań, więc nie pozwól, aby nasza (ograniczona!) wyobraźnia Cię powstrzymała. Ułatwiając zarządzanie częściowymi aktualizacjami, możesz ograniczyć ilość powtarzalnego kodu, uprościć aktualizacje i odkryć nowe możliwości internetu.