乱序 HTML 流是一种允许用户在页面完全加载之前即可查看并与之交互的模式。该模式正逐渐被引入 Web 浏览器。根据提案,当数据通过声明式 HTML 或相应的 JavaScript API 传入时,浏览器会实时更新占位符的内容。Chrome 150 已经正式推出这些声明式功能,而 Safari 和 Firefox 也已经表示将予以支持。
该声明式提案通过标准 元素中新增的 for 属性引入了乱序 HTML 流。开发者可以声明单个插入点(例如 )或者封装临时回退内容(例如 Loading profile...)。
当服务器稍后以流的方式传输文档中匹配的 时,HTML 解析器会匹配该标识符,移除 和 标记以及它们之间的所有中间回退节点,并将模板内容插入到那个 DOM 位。开发者还可以在模板中包含处理指令,用于支持多次更新:
<ul id="results"> <?start name="results"> Loading… <?end>><template for="results"> <li>Result One</li> marker name="results">>...<template for="results"> >Result Two> marker name="results">>...在解析并处理完模板 HTML 之后,页面的最终 HTML 代码如下:
<ul id="results"> <li>Result One</li> >Result Two> marker name="results">>严格来说,为了防止跨组件注入攻击(例如,文档中其他位置的不受信任的标记劫持敏感表单或导航目标), 只能修补位于其直接父元素内(即其直接同级元素及其子元素)的处理指令(以 分隔符开头的标记节点)。作为规范中明确规定的例外情况,如果将模板直接放置在 标签之下,那么该模板将获得全局文档作用域,这样延迟更新就可以作用于 标签内部或嵌套在结构容器中的元素。
为了将流式处理工作流扩展到客户端脚本,该方案将这些标记原语与一套统一的静态和流式 DOM 插入方法进行了结合。该规范定义了一组可预测的操作矩阵:setHTML、replaceWithHTML、beforeHTML、prependHTML、appendHTML 和 afterHTML,以及相应的流式处理方法(streamHTML、streamAppendHTML 等)和 *Unsafe 变体。例如,调用 streamHTMLUnsafe() 会返回一个 WritableStream,将传入的块数据增量地传输到内部的 HTML 片段解析器中。Fetch API 通过辅助方法 response.textStream() 对此进行了补充:
const feedContainer = document.querySelector("#feed-container");const response = await fetch("/api/feed-stream");await response.textStream().pipeTo( feedContainer.streamHTMLUnsafe({ runScripts: false }));通过将乱序交付和渲染功能内化到浏览器引擎中,该提案对长期以来前端框架以不同方式实现的渲染技术进行了标准化。这些技术最初由 Facebook 的 BigPipe 于 2009 年率先提出,随后通过 React(搭配 Suspense 流式传输)和 Next.js 等框架得以普及,尽管具体的实现方式各异,但其根本目标是一致的:防止页面中计算耗时的部分阻塞整个页面的加载。
原文链接:https://www.infoq.com/news/2026/09/native-deferred-html-streaming/