Deklaratywne aktualizacje częściowe

Data publikacji: 19 maja 2026 r., ostatnia aktualizacja: 8 września 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.

W przypadku internetu wydajność jest niezwykle ważna ze względu na charakter klienta-serwera. Jednak w celu obejścia tego uporządkowanego charakteru HTML często dokonuje się nieoptymalnych wyborów, co spowalnia działanie. Obejmuje to 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.

Pierwsze 2 nowe zestawy interfejsów API ułatwiają dostarczanie kodu HTML w mniej liniowy sposób, zarówno w przypadku kolejności w samym 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. 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ą.

Strumieniowanie poza kolejnością

Browser Support

  • Chrome: 150.
  • Edge: 150.
  • Firefox: not supported.
  • Safari: not supported.

Source

Pierwszy zestaw zmian to nowe interfejsy API do przesyłania strumieniowego w nieodpowiedniej kolejności, które używają symboli zastępczych instrukcji przetwarzania i elementu HTML <template> z atrybutem for. 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 kodu HTML. Na przykład, gdy przeglądarka zobaczy instrukcję przetwarzania <?marker name="placeholder">, nie robi nic od razu – podobnie jak wcześniej – ale można się do niej odwołać później.

Element <template> z for atrybutem wyszukuje odpowiednie instrukcje przetwarzania z atrybutem name i zastępuje treść. W tym przypadku po przeanalizowaniu DOM wygląda tak (pomijając pewne różnice w znakach odstępu):

<div>
  Here is some <em>HTML content</em>!
</div>

Oprócz atrybutu <?marker> dla zamienników istnieją też znaczniki zakresu <?start><?end>, które umożliwiają wyświetlanie tymczasowej treści zastępczej przed przetworzeniem szablonu:

<div>
  <?start name="another-placeholder">
  Loading…
  <?end>
</div>

...

<template for="another-placeholder">
  Here is some <em>HTML content</em>!
</template>

W takim przypadku ciąg Loading… wyświetla się do momentu pojawienia się znaku <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 przeanalizowaniu i przetworzeniu otrzymasz ten kod HTML:

<ul id="results">
  <li>Result One</li>
  <li>Result Two</li>
  <?marker name="results">
</ul>

Z ostateczną instrukcją przetwarzania na końcu, na wypadek gdyby do dokumentu dodano później więcej symboli zastępczych <template for="results">.

Dlaczego instrukcje przetwarzania zamiast standardowych elementów HTML?

To częste pytanie wśród osób, które dopiero zaczynają korzystać z tego interfejsu API. Sugerujemy użycie elementów <slot> lub nawet <template>. Początkowa wersja tej propozycji korzystała ze standardowych elementów HTML, ale w miarę rozwoju projektu instrukcje przetwarzania zostały zmienione. Instrukcje przetwarzania umożliwiają zastosowanie poprawki bez wpływu na DOM. Dzięki temu można go używać w <head> – np. w przypadku aktualizacji <title> – a nawet w innych elementach, takich jak <table> (np. w celu dodania opcjonalnych dodatkowych wierszy).

Chociaż składnia instrukcji przetwarzania jest nieznana wielu programistom stron internetowych, oferują one znacznie większą elastyczność i mniejsze ryzyko problemów ze zgodnością wsteczną. Są one już używane w XML i dzięki tej propozycji stanowią teraz część standardu HTML.

Prezentacja

W tym filmie pokazujemy, jak zaimplementować podstawową aplikację do albumu ze zdjęciami za pomocą strumieniowego HTML:

Demo albumu ze zdjęciami zaimplementowany za pomocą strumieniowania w nieprawidłowej kolejności (źródło)

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 frameworki takie jak Astro, czyli architektura wyspowa, w której komponenty są renderowane niezależnie na statycznym kodzie HTML. Interfejs <template for> API umożliwia bezpośrednie obsługiwanie treści statycznych w HTML w podobny sposób. Frameworki JavaScriptu mogą też używać tego do bardziej interaktywnych wysp lub do 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, które wymagają 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ści są często opóźniane lub wymagają 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ć droższe i dynamiczne treści.
  • HTML może być dostarczany w optymalnej kolejności, co zwiększa szybkość wczytania strony. Możesz nawet zmienić zamówienie, gdy jest już gotowe. Przykładem są mega menu, które są popularną funkcją nawigacyjną zawierającą dużo kodu HTML, którego użytkownik nie zobaczy, dopóki strona nie stanie się interaktywna. Ten duży fragment kodu HTML można dostarczyć później w dokumencie HTML, aby nadać priorytet ważniejszemu kodowi HTML potrzebnemu do początkowego wczytania strony. Kolejność nie jest już barierą 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 <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 jak setHTML lub właściwości innerHTML „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 przesyłania strumieniowego za pomocą metod takich jak streamHTMLUnsafe (o których powiemy za chwilę) nie ma fragmentu pośredniego, więc szablony mogą zastępować istniejące treści.

Stan standaryzacji

Atrybut <template for> jest częścią standardu HTML, ale nie jest jeszcze obsługiwany we wszystkich przeglądarkach.

Potencjalne dodatki w przyszłości

Oto niektóre potencjalne przyszłe dodatki, które są rozważane:

  • Po stronie klienta Na przykład <template for="footer" src="/partials/footer.html"> lub nawet bez poprawki <template src="/partials/footer.html">. Więcej informacji znajdziesz w filmie z wyjaśnieniem. Ta funkcja jest dostępna za flagą chrome://flags/#enable-experimental-web-platform-features.
  • 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 opublikował 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 obejmuje to najczęstsze przypadki użycia. Witryny powinny być nadal testowane w innych przeglądarkach.

Nowe metody wstawiania kodu HTML i streamingu

Nie wszystkie treści można dostarczyć w formacie HTML. Drugi aspekt prac Chrome w tym obszarze ma na celu ułatwienie aktualizowania treści za pomocą JavaScriptu.

Istnieje już wiele sposobów na dynamiczne wstrzykiwanie kodu HTML do istniejącego dokumentu za pomocą JavaScriptu:

  • setHTML
  • setHTMLUnsafe
  • innerHTMLouterHTML
  • createContextualFragment
  • insertAdjacentHTML

Wszystkie działają jednak nieco inaczej, a ich subtelności i różnice mogą nie zawsze być brane pod uwagę przez programistów:

  • Czy nowe treści zastępują poprzednie, czy są do nich dołączane?
  • Czy oczyszczają potencjalnie niebezpieczny kod HTML, np. przez ucieczkę z tagów <script>?
  • Jeśli nie, czy <script> powinien biec?
  • Jak działają w połączeniu z zaufanymi typami?

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 kodu HTML znanego z wyprzedzeniem, mimo że pojawiały się prośby o umożliwienie strumieniowania kodu HTML. W praktyce oznacza to, że przed wstawieniem treści musisz pobrać je w całości, podczas gdy jedną z 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

Browser Support

  • Chrome: behind a flag.
  • Edge: behind a flag.
  • Firefox: not supported.
  • Safari: not supported.

Chrome opracował zestaw nowych interfejsów API i rozszerzeń dotychczasowych interfejsów setHTMLsetHTMLUnsafe, które upraszczają ten proces, a także wprowadzają funkcję przesyłania strumieniowego.

Są one gotowe do testowania przez programistów od Chrome 148 przy użyciu flagi chrome://flags/#enable-experimental-web-platform-features, a ich wprowadzenie jest planowane w Chrome 155.

Istnieją metody ustawiania lub zastępowania, a także metody wstawiania treści przed istniejącym kodem HTML lub po nim. Każda metoda ma odpowiednik 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);
Nowe metody wstawiania i strumieniowania

Istnieją też wersje Unsafe, które omówimy wkrótce. 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());

textStream() metoda wygodna

Browser Support

  • Chrome: 151.
  • Edge: 151.
  • Firefox: not supported.
  • Safari: not supported.

Dodaliśmy też textStream wygodną metodę, która umożliwia strumieniowanie bezpośrednio bez konieczności wykonywania pośredniego kroku TextDecoderStream():

const contentElement = document.querySelector('#content-to-update');
const response = await fetch('/api/content.html');

response.textStream().pipeTo(contentElement.streamHTMLUnsafe());

options

Argument options umożliwia określenie niestandardowego sanitizer, którego domyślna wartość to default, co oznacza domyślną konfigurację 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);
„Niebezpieczne” metody wstawiania i streamingu

Te „niebezpieczne” metody domyślnie wyłączają narzędzie do czyszczenia, ale w razie potrzeby możesz określić niestandardowe narzędzie. Te metody umożliwiają też uruchamianie skryptów z opcjonalną opcją runScripts, która domyślnie ma wartość false.

Podobnie jak setHTML, setHTMLUnsafe jest istniejącą metodą, 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 „niebezpieczne” jest to działanie, zależy od tego, jak 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 filtr.

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ą obecnej architektury SPA jest to, że nie korzysta ona ze strumieniowego charakteru początkowych wczytań HTML – aż do teraz.
  • Wstawianie typowej treści, takiej jak stopki HTML. Korzystanie z interfejsów JavaScript API umożliwia pobieranie częściowych odpowiedzi i wstawianie ich na stronie, 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 funkcji czyszczącej do dowolnej operacji ustawiania HTML. Więcej informacji o integracji zaufanych typów znajdziesz w filmie z wyjaśnieniem.
  • Podobnie jak w przypadku <template for>, przenoszenie elementów, które są przesyłane strumieniowo, może mieć nieoczekiwane konsekwencje lub powodować błędy strumienia.
  • streamHTMLUnsafe dział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 skrypty defer do końca strumienia.

Stan standaryzacji

Nowsze metody wstawiania i strumieniowania są w trakcie dodawania do standardu HTML, ale nie są jeszcze obsługiwane we wszystkich przeglądarkach.

Kod polyfill

Zespół Chrome opublikował 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 polyfill nie przesyła strumieniowo, tylko buforuje i stosuje po zakończeniu. Jest to raczej kod polyfill dla kształtu interfejsu API niż dla funkcjonalności.

Ustawienie bezpiecznych treści zależy też od setHTMLinterfejsu Sanitizer API, który nie jest obsługiwany w Safari.

Używaj ich razem

Są to 2 oddzielne 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ń JavaScript 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.

Bez wątpienia oba te interfejsy API mają 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.

W ramach projektu Declarative Partial Updates pracujemy nad kilkoma innymi interfejsami API Chrome, ale cieszymy się, że możemy udostępnić Ci te 2 pierwsze. Będziemy Cię informować o nowościach w tej dziedzinie.