순서가 지정되지 않은 (OOO) HTML 스트리밍 (선언적 부분 업데이트라고도 함)은 기존의 '위에서 아래로' 진행되는 선형 HTML 처리 방식을 대체하는 기술입니다. 이를 통해 개발자는 문서의 앞부분에서 자리표시자를 정의하고 동일한 네트워크 스트림에서 나중에 도착하는 콘텐츠 또는 새로운 명령형 JavaScript 스트리밍 API를 통해 콘텐츠를 '패치'할 수 있습니다.
간략 개요
이 기능은 두 가지 기본 메커니즘으로 구성됩니다.
- 선언적 패치 적용 (HTML 기반): 새로운 처리 명령어 (
<?marker>,<?start>,<?end>)와<template for>를 사용하여 서버에서 스트리밍되는 DOM의 콘텐츠를 교체합니다. - 명령형 설정 및 스트리밍 (JS 기반): HTML을 설정하거나 읽기 가능한 스트림을 네이티브 성능 및 선택적 스크립트 실행을 통해 DOM 요소에 직접 파이프할 수 있는 새로운 메서드 모음 (예:
streamHTML(),setHTMLUnsafe())입니다.
권장사항
- 스크롤 없이 볼 수 있는 부분에 표시되는 콘텐츠에 우선순위 지정: 중요한 UI (헤더, 히어로, 기본 탐색, 기본 콘텐츠)를 먼저 스트리밍합니다. 댓글, 광고, 관련 콘텐츠와 같이 '비용이 많이 들거나' 우선순위가 낮은 구성요소에는 자리표시자를 사용합니다.
- 네이티브 로드 상태 구현:
<?start>및<?end>마커를 사용하여 대체 콘텐츠를 래핑합니다. 해당<template for>가 도착하면 브라우저가 이러한 마커 사이의 모든 항목을 자동으로 대체합니다. - 누적 레이아웃 이동 (CLS) 최소화: 항상 자리표시자에 안정적인 크기를 제공합니다. 최종 콘텐츠 크기를 알 수 없는 경우 스켈레톤 화면이나 CSS
aspect-ratio를 사용하여 공간을 예약하고 갑작스러운 이동을 방지하세요. - 접근성 및 포커스 관리: 순서가 맞지 않는 업데이트는 스크린 리더 사용자에게 혼란을 줄 수 있습니다. 중요한 업데이트에는
aria-live영역을 사용하고 활성 요소가 포함된 플레이스홀더가 대체되더라도 포커스가 사라지지 않도록 합니다.
구현 세부정보
1. 선언적 HTML 마커
브라우저는 콘텐츠를 패치해야 하는 위치를 식별하기 위해 특정 처리 명령어를 찾습니다.
<!-- A simple insertion point -->
<div id="sidebar">
<?marker name="dynamic-comments">
</div>
<!-- A replacement range with loading state -->
<main>
<?start name="main-content">
<div class="skeleton">Loading content...</div>
<?end>
</main>
... (other content) ...
<!-- Later in the same stream, provide the content -->
<template for="dynamic-comments">
<div class="comments">...</div>
</template>
<template for="main-content">
<article>
<h1>The Real Content</h1>
<p>This replaces the skeleton div automatically.</p>
</article>
</template>
<template>가 삽입 지점을 대체하면 해당 삽입 지점은 더 이상 존재하지 않으며 재사용할 수 없습니다. 하지만 <template>에는 스트림에서 나중에 사용할 수 있는 삽입 지점이 포함될 수 있습니다.
<?start name="replaced-content">
<div class="skeleton">
<?end>
<!-- Later in the same stream, provide initial content -->
<template for="replaced-content">
<?start name="replaced-content">
<div>Quickly computed result</div>
<?end>
</template>
<!-- Later in the same stream, provide full content -->
<template for="replaced-content">
<?start name="replaced-content">
<div>Full result</div>
<?end>
</template>
2. 명령형 JS 스트리밍
브라우저는 정적으로 (문자열에서) 또는 스트림을 통해 DOM을 업데이트하는 24가지 메서드 (6가지 작업, 각각 4가지 변형)를 제공합니다.
API 참조 매트릭스
| 작업 | 정적 (안전) | Streaming (Safe)[스트리밍(안전)] | 정적 (안전하지 않음) | 스트리밍 (안전하지 않음) |
|---|---|---|---|---|
| 세트 | setHTML() |
streamHTML() |
setHTMLUnsafe() |
streamHTMLUnsafe() |
| 바꾸기 | replaceWithHTML() |
streamReplaceWithHTML() |
replaceWithHTMLUnsafe() |
streamReplaceWithHTMLUnsafe() |
| 전 | beforeHTML() |
streamBeforeHTML() |
beforeHTMLUnsafe() |
streamBeforeHTMLUnsafe() |
| 앞에 추가 | prependHTML() |
streamPrependHTML() |
prependHTMLUnsafe() |
streamPrependHTMLUnsafe() |
| 추가 | appendHTML() |
streamAppendHTML() |
appendHTMLUnsafe() |
streamAppendHTMLUnsafe() |
| 후 | afterHTML() |
streamAfterHTML() |
afterHTMLUnsafe() |
streamAfterHTMLUnsafe() |
주요 개념
- 안전한 콘텐츠와 안전하지 않은 콘텐츠:
- 안전한 메서드 (예:
setHTML())는 기본적으로 내장된 살균기를 사용하여<script>태그와 같은 잠재적으로 위험한 콘텐츠를 제거합니다. 옵션에 커스텀Sanitizer객체를 전달하여 기본 살균기 외에 적용할 수 있습니다. - 안전하지 않은 메서드 (예:
setHTMLUnsafe())는 기본적으로 정제하지 않지만 맞춤Sanitizer를 전달할 수 있습니다. 새 콘텐츠에서 스크립트를 실행하려면 옵션에서{ runScripts: true }를 명시적으로 전달해야 합니다. 중요: 안전한 방법이 작동하지 않는 신뢰할 수 있는 콘텐츠에만 안전하지 않은 방법을 사용하세요.
- 안전한 메서드 (예:
- 정적 및 스트리밍:
- 정적 메서드는 문자열 (또는
TrustedHTML)을 가져와 즉시 적용합니다. - 스트리밍 메서드는
WritableStream를 반환합니다. 이를 통해 콘텐츠 (예:fetch응답)를 DOM으로 직접 파이프할 수 있으며, 브라우저는 청크가 도착할 때마다 점진적으로 렌더링합니다.
- 정적 메서드는 문자열 (또는
예: 가져오기 응답 스트리밍
수동 청크 처리 없이 가져오기 응답을 DOM에 직접 파이프할 수 있습니다.
const main = document.querySelector('main');
const response = await fetch('/api/partial-update');
// Pipe the stream directly into the element
await response.body
.pipeThrough(new TextDecoderStream())
.pipeTo(main.streamHTMLUnsafe({ runScripts: true }));
// Or use the `textStream()` convenience method which streams directly without needing the intermediate `TextDecoderStream()` step
await response
.textStream()
.pipeTo(main.streamHTMLUnsafe({ runScripts: true }))
사용 사례 참조 매트릭스
- 아일랜드 아키텍처: 전체 프레임워크 런타임 없이 정적 HTML 위에 독립적인 대화형 구성요소를 하이드레이션합니다.
- 지연된 '고비용' 블록: 페이지의 셸을 즉시 전송하고 데이터베이스가 많이 사용되는 구성요소를 사용 가능해지는 대로 스트리밍합니다.
- 단일 페이지 애플리케이션 (SPA) 업데이트: 전체 JSON 페이로드와 수동 DOM 생성을 기다리는 대신
streamHTML()를 사용하여 SPA에서 대규모 UI 전환을 스트리밍합니다.
안티패턴 및 경고 (금지사항)
- 모든 상황에 OOO 스트리밍을 사용하지 마세요. 페이지를 과도하게 단편화하면 스트림의 복잡성이 증가하고 브라우저가 작은 노드를 패치하는 데 너무 많은 시간을 소비하는 경우 콘텐츠가 지연될 수 있습니다.
- 신뢰할 수 있는 유형을 무시하지 마세요. 신뢰할 수 있는 유형이 적용된 환경에서
*Unsafe메서드를 사용하는 경우 필요한 경우 정제된 정책 객체를 전달해야 합니다. - 스크립트 실행 순서를 가정하지 마세요.
<template for>내의 스크립트는 문서에 패치되는 즉시 실행됩니다. 다른 지연된 템플릿과 관련하여 특정 순서로 실행되는 것에 의존하지 마세요. - 폴리필 전략 없이 사용하지 마세요. 이 기능이 Baseline이 될 때까지 대체 기능을 사용하거나 폴리필 (
html-setters-polyfill및template-for-polyfill)을 사용하여 필요한 브라우저를 지원하세요.
대체 전략
template-for-polyfill 및 html-setters-polyfill와 같은 폴리필을 사용하여 지원되지 않는 브라우저의 API 노출 영역을 에뮬레이션할 수 있습니다.
html-processing-instructions 지원이 없는 브라우저는 <?marker>, <?start>, <?end>를 주석으로 파싱합니다. template-for-polyfill는 이러한 주석을 마커로 인식하므로 모든 브라우저에서 동일한 처리 명령 구문을 유지합니다. 지원되지 않는 브라우저의 경우 마커를 HTML 주석이나 요소로 다시 작성하지 마세요.