Опубликовано: 19 мая 2026 г.
Интернет давно отошел от статической, основанной на документах среды, с которой он начинался. Современные многофункциональные веб-приложения используются всеми по самым разным причинам: от общения и покупок до потребления контента и управления нашей сложной жизнью.
HTML, несмотря на все свои достижения, по-прежнему отображается в порядке сверху вниз, практически не обращая внимания на то, когда контент готов или когда пользователь его просматривает. CSS позволяет изменять порядок контента, но часто с существенными побочными эффектами, влияющими на доступность. JavaScript позволяет манипулировать DOM с помощью различных API, чтобы в некоторой степени обойти это ограничение, но такие API часто требуют многословного синтаксиса или построения деревьев DOM для интеграции в HTML.
Производительность невероятно важна для веб-разработки, учитывая клиент-серверную природу среды, но часто принимаются неоптимальные решения, чтобы обойти эту последовательную структуру HTML, что замедляет производительность. Это включает в себя ожидание полной готовности всей страницы или использование ресурсоемкого фреймворка для асинхронной доставки компонентов. Популярность JavaScript-фреймворков показывает, что веб-разработчики предпочитают компонентно-ориентированную модель жесткой документоориентированной модели, унаследованной от истоков веб-разработки.
Команда Chrome рассматривает эту проблему и разрабатывает новые дополнения для веб-платформы под названием «Декларативные частичные обновления» .
Два новых набора API упрощают передачу HTML-кода в менее линейном режиме, будь то в произвольном порядке в самом HTML-документе или с помощью более простых способов динамической вставки HTML в существующие документы с использованием новых API JavaScript. Они готовы к тестированию разработчиками начиная с Chrome 148 с помощью флага chrome://flags/#enable-experimental-web-platform-features . Также доступны полифилы, позволяющие использовать эти новые API сразу же, даже в браузерах, которые их еще не поддерживают.
Эти дополнения к веб-платформе стандартизируются благодаря положительным отзывам от других производителей браузеров и различных каналов стандартизации. Соответствующие стандарты в настоящее время обновляются, чтобы включить эти новые API.
Потоковое вещание не по порядку
Первая группа изменений включает в себя новые API для потоковой передачи данных в произвольном порядке с использованием HTML-элемента <template> и заполнителей инструкций обработки. Например:
<div>
<?marker name="placeholder">
</div>
...
<template for="placeholder">
Here is some <em>HTML content</em>!
</template>
Инструкции по обработке существовали в XML уже давно, но в HTML они рассматривались как комментарии и игнорировались. Новый API меняет это и переносит инструкции по обработке в HTML. Когда браузер видит инструкции по обработке <?marker name="placeholder"> , он не выполняет никаких действий сразу — как и раньше — но на них можно ссылаться позже.
Элемент <template> находит соответствующие инструкции обработки с помощью атрибута name и заменяет содержимое. В этом случае после парсинга DOM-структура выглядит следующим образом:
<div>
Here is some <em>HTML content</em>!
</div>
Помимо атрибута <?marker> для замен, существуют также маркеры диапазона <?start> и <?end> , которые позволяют отображать временное содержимое-заполнитель до обработки шаблона:
<div>
<?start name="another-placeholder">
Loading…
<?end>
</div>
...
<template for="another-placeholder">
Here is some <em>HTML content</em>!
</template>
В этом случае Loading… отображается до тех пор, пока не будет показан <template> , после чего она заменяется новым содержимым.
Также можно включать инструкции по обработке в шаблоны, что позволяет выполнять множественные обновления:
<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>
...
В результате после обработки получается следующий HTML-код:
<ul id="results">
<li>Result One</li>
<li>Result Two</li>
<?marker name="results">
</ul>
В конце приводится инструкция по окончательной обработке на случай, если в документ позже будут добавлены дополнительные <template for="results"> .
Демо
В этом видео реализовано базовое приложение для создания фотоальбомов с использованием потокового HTML:
И статус, и фотографии передаются в HTML-код после первоначальной разметки.
Варианты использования
Существует множество вариантов применения такого способа внесения изменений в HTML-код в произвольном порядке в сочетании с потоковой передачей HTML:
- Островная архитектура. Распространенный шаблон, популяризированный такими фреймворками, как Astro, — островная архитектура , в которой компоненты независимо загружаются поверх статического HTML. API
<template for>позволяет обрабатывать статическое содержимое аналогичным образом непосредственно в HTML. JavaScript-фреймворки также могут использовать это для создания более интерактивных островных архитектур или для обработки компонентов. - Доставка контента по мере его готовности. Благодаря такой изолированной архитектуре контент может передаваться потоком по мере готовности, а не задерживаться для контента, требующего дополнительной обработки, например, поиска в базе данных. Хотя многие платформы позволяют передавать HTML в потоковом режиме, последовательная структура HTML приводит к тому, что контент часто задерживается или приходится прибегать к сложным манипуляциям с DOM на JavaScript. Теперь вы можете передавать статический контент, пока он ожидает, а затем добавлять более ресурсоемкий контент в конце потока HTML.
- HTML-код можно размещать в оптимальном порядке для обеспечения высокой скорости загрузки страницы. Более того, порядок можно изменять даже после завершения загрузки. Например, мега-меню — распространенный элемент навигации, содержащий большой объем HTML-кода, который пользователь увидит только после того, как страница станет интерактивной. Этот большой фрагмент HTML-кода можно разместить позже в документе, чтобы отдать приоритет более важному HTML-коду, необходимому для первоначальной загрузки страницы. Порядок больше не является препятствием для HTML-кода.
Это лишь некоторые примеры использования, и очень интересно посмотреть, для чего разработчики будут применять этот новый API.
Ограничения и тонкости
API содержит ряд ограничений и нюансов, о которых следует помнить:
- В целях безопасности
<template for>может обновлять инструкции обработки только внутри того же родительского элемента. Добавление<template for>непосредственно к элементу<body>дает ему доступ ко всему документу (включая<head>). - Инструкция обработки
<?end>является необязательной, и если она отсутствует, содержимое между элементом<?start>и концом содержащего его элемента будет заменено. - Перемещение инструкций обработки после начала потоковой передачи
<template for>также может привести к неожиданным последствиям, поскольку новый контент продолжит передаваться в старое местоположение. - Обратите внимание, что при динамической вставке
<template for>с помощью таких методов, какsetHTMLилиinnerHTML, "родительским" элементом шаблона при его анализе является промежуточный фрагмент документа. Это означает, что вставка HTML с использованием этих методов не может изменять существующий DOM, и патчинг происходит "на месте" внутри фрагмента. Однако при потоковой передаче с использованием таких методов, какstreamHTMLUnsafe(которые мы сейчас рассмотрим!), промежуточного фрагмента нет, поэтому шаблоны могут заменять существующее содержимое.
Возможные дополнения в будущем
В числе потенциальных дополнений, которые находятся на стадии рассмотрения, можно выделить следующие:
- Включается на стороне клиента. Например,
<template for="footer" patchsrc="/partials/footer.html">. - Пакетная обработка. На стороне клиента можно также расширить возможности включения фрагментов для обработки пакетной обработки, чтобы обеспечить одновременное выполнение нескольких обновлений.
- Предотвращение перезаписи контента, который не будет изменяться. Этого можно достичь с помощью номера ревизии контента или версионирования. Это позволит сохранять состояние между изменениями маршрутов или другими обновлениями, вместо сброса контента.
- Очистка данных во время установки патчей. Например,
<template for=icon safe><svg id="from-untrusted-source">...</svg></template>
Полиэфирный наполнитель
Команда Chrome выпустила template-for-polyfill доступный в npm , чтобы сайты могли сразу же использовать эту новую функциональность, еще до того, как она появится в других браузерах.
Есть некоторые ограничения , поскольку он не может напрямую обновлять HTML-парсеры браузеров, но наиболее распространенные сценарии использования охвачены. Тем не менее, сайты следует тестировать в других браузерах.
Обновлены методы вставки и потоковой передачи HTML-кода.
Не весь контент можно передать в формате HTML. Вторая часть работы, которую Chrome проводит в этой области, направлена на упрощение обновления контента с помощью JavaScript.
Уже существует множество способов динамического внедрения HTML-кода в существующий документ с помощью JavaScript:
-
setHTML -
setHTMLUnsafe - сеттеры
innerHTMLиouterHTML -
createContextualFragment -
insertAdjacentHTML
Однако все они работают несколько по-разному, с нюансами и различиями, которые разработчики не всегда могут учитывать:
- Новое содержимое перезаписывает или добавляется?
- Они очищают потенциально опасный HTML-код, например, экранируя теги
<script>? - В противном случае, следует ли запустить
<script>? - Как они взаимодействуют с TrustedTypes?
Немногие разработчики, честно взглянув на эти API, смогли бы с уверенностью ответить на эти вопросы по каждому из них.
Существенным ограничением является то, что их можно использовать только для полного набора HTML-кода, известного заранее, при условии, что были сделаны запросы на потоковую передачу HTML . На практике это означает, что вам нужно загрузить весь контент перед его вставкой, тогда как одним из сильных сторон HTML является возможность мгновенной потоковой передачи контента. Это можно частично обойти, разделив полезную нагрузку или используя устаревшие, неоптимальные методы, такие как document.write , но они создают свои собственные проблемы.
Новый набор статических и потоковых API.
Chrome предложил набор новых API и расширений для существующих функций setHTML и setHTMLUnsafe , которые упрощают этот процесс, а также вводят функциональность потоковой передачи данных:
Существуют методы для установки или замены, а также методы для вставки контента до или после существующего HTML-кода. Для каждого метода есть эквиваленты в потоке:
| Действие | Статический | Стриминг |
|---|---|---|
| Задайте HTML-содержимое элемента | setHTML(html, options); | streamHTML(options); |
| Замените весь элемент этим HTML-кодом. | replaceWithHTML(html, options); | streamReplaceWithHTML(options); |
| Добавьте HTML-код перед элементом. | beforeHTML(html, options); | streamBeforeHTML(options); |
| Добавьте HTML-код в качестве первого дочернего элемента. | prependHTML(html, options); | streamPrependHTML(options); |
| Добавьте HTML-код в качестве последнего дочернего элемента. | appendHTML(html, options); | streamAppendHTML(options); |
| Добавьте HTML-код после элемента. | afterHTML(html, options); | streamAfterHTML(options); |
Существуют также Unsafe версии, о которых мы поговорим чуть позже. Хотя их может показаться много (особенно если учесть Unsafe аналоги), единообразная система именования делает более очевидным назначение каждой из них по сравнению с ранее упомянутыми несвязанными методами.
Статические версии принимают новый HTML-код в качестве аргумента DOM-строки, а также необязательные параметры:
const newHTML = "<p>This is a new paragraph</p>";
const contentElement = document.querySelector('#content-to-update');
contentElement.setHTML(newHTML);
Потоковые версии работают с API Streams, например, с помощью метода 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();
Или, в качестве альтернативы, из ответа на запрос, используя цепочки каналов :
const contentElement = document.querySelector('#content-to-update');
const response = await fetch('/api/content.html');
response.body
.pipeThrough(new TextDecoderStream())
.pipeTo(contentElement.streamHTMLUnsafe());
Мы также планируем добавить удобный метод , позволяющий осуществлять прямую потоковую передачу без необходимости использования промежуточного шага TextDecoderStream() .
Аргумент options позволяет указать пользовательский sanitizer , который по умолчанию использует конфигурацию санитайзера по умолчанию default Он используется следующим образом:
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});
«Небезопасные» методы
Существуют также «небезопасные» версии каждого из API:
| Действие | Статический | Стриминг |
|---|---|---|
| Задайте HTML-содержимое элемента | setHTMLUnsafe(html,options); | streamHTMLUnsafe(options); |
| Замените весь элемент этим HTML-кодом. | replaceWithHTMLUnsafe(html, options); | streamReplaceWithHTMLUnsafe(options); |
| Добавьте HTML-код перед элементом. | beforeHTMLUnsafe(html, options); | streamBeforeHTMLUnsafe(options); |
| Добавьте HTML-код в качестве первого дочернего элемента. | prependHTMLUnsafe(html, options); | streamPrependHTMLUnsafe(options); |
| Добавьте HTML-код в качестве последнего дочернего элемента. | appendHTMLUnsafe(html, options); | streamAppendHTMLUnsafe(options); |
| Добавьте HTML-код после элемента. | afterHTMLUnsafe(html, options); | streamAfterHTMLUnsafe(options); |
Эти «небезопасные» методы по умолчанию отключают санитайзер (при желании можно указать собственный санитайзер), а также позволяют запускать скрипты с необязательной опцией runScripts (по умолчанию — false ).
Подобно методу setHTML , метод setHTMLUnsafe уже существует, но в него добавлен параметр параметров runScripts , позволяющий использовать его при выполнении скриптов:
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});
Использование слова «небезопасный» в описании метода призвано напомнить разработчикам о потенциальном риске и о том, как они могут захотеть очистить или ограничить работу скриптов, а не утверждать, что эти методы не следует использовать.
Насколько это «небезопасно», зависит от того, насколько надежны входные данные. Все статические методы Unsafe работают как с DOM String, так и TrustedHTML в качестве аргументов html , а также позволяют использовать санитайзеры. Однако в случае с runScript основная цель — разрешить использование скриптов, поэтому по умолчанию санитайзер не используется.
Варианты использования
Эти новые API упрощают разработчикам добавление HTML-кода на существующие страницы, предоставляя новые API с согласованными именами и параметрами. API для потоковой передачи данных обеспечивают преимущества в производительности, поскольку не нужно ждать, пока весь новый контент станет доступен платформе.
Примеры использования включают:
- Динамическая потоковая передача больших объемов контента в одностраничных приложениях (SPA). Как уже упоминалось, существенным недостатком современных SPA является то, что они не могли воспользоваться преимуществами потоковой передачи при первоначальной загрузке HTML-кода — до настоящего времени!
- Вставка распространенного контента, такого как HTML-футеры. Использование API JavaScript позволяет подтягивать частичные шаблоны и вставлять их на страницу, используя преимущества кэширования, вместо того, чтобы повторять их на каждой загружаемой странице. Однако, учитывая зависимость от JavaScript для работы, этот метод следует использовать только для контента, который не будет виден при первоначальной загрузке.
Повторюсь, это всего лишь пара примеров, и нам не терпится увидеть, что вы придумаете!
Ограничения и тонкости
Эти новые API также содержат ряд ограничений и нюансов, о которых следует помнить:
- Для интеграции потоковой обработки данных с API Trusted Types требуется использовать новый метод
createParserOptions, который позволяет внедрять санитайзер в любую операцию настройки HTML. Более подробную информацию об интеграции Trusted Types см. в пояснительной статье. - Подобно
<template for>элементов, передаваемых потоком, это может привести к неожиданным последствиям или ошибкам потока. -
streamHTMLUnsafeво многом работает аналогично основному парсеру, включая обработку инструкций<template for>по мере их добавления в основной документ и откладывание выполнения скриптовdeferдо конца потока.
Полиэфирный наполнитель
Команда Chrome выпустила html-setters-polyfill , доступный в npm , чтобы сайты могли сразу же использовать эту новую функциональность, еще до того, как она появится в других браузерах.
Обратите внимание, что этот полифил не использует потоковую передачу, а вместо этого буферизует данные и применяет их по завершении. Это скорее полифил для структуры API, чем для функциональности.
Кроме того, настройка безопасного контента зависит от setHTML и API Sanitizer , которые не поддерживаются в Safari.
Используйте их оба вместе.
Хотя это два отдельных API, настоящая мощь заключается в их объединении. Передавая новые элементы <template for> в HTML, вы можете динамически обновлять различные части контента, не прибегая к отдельным ссылкам на DOM в JavaScript для каждой из них.
Простейшую загрузку страницы в стиле SPA можно реализовать, загрузив страницу-шаблон с инструкциями по обработке, а затем передавая шаблоны каждой новой страницы в конец HTML-кода для вставки в эти инструкции по обработке.
Несомненно, у обоих этих API гораздо больше потенциала и вариантов применения, поэтому не позволяйте нашей (ограниченной!) фантазии вас ограничивать. Упростив управление частичными обновлениями, вы можете сократить количество шаблонного кода, упростить обновления и открыть новые возможности для веб-разработки!