Truyền trực tuyến HTML không theo thứ tự (OOO) (còn gọi là Cập nhật một phần theo khai báo) là một giải pháp thay thế cho quy trình xử lý tuyến tính "từ trên xuống dưới" truyền thống của HTML. API này cho phép nhà phát triển xác định phần giữ chỗ sớm hơn trong tài liệu và "vá" phần giữ chỗ bằng nội dung đến sau trong cùng một luồng mạng hoặc thông qua các API truyền trực tuyến JavaScript bắt buộc mới.
Tổng quan nhanh
Tính năng này bao gồm hai cơ chế chính:
- Vá khai báo (dựa trên HTML): Sử dụng các lệnh xử lý mới (
<?marker>,<?start>,<?end>) và<template for>để hoán đổi nội dung trong DOM khi nội dung đó truyền trực tuyến từ máy chủ. - Thiết lập và truyền trực tuyến bắt buộc (dựa trên JS): Một bộ phương thức mới (ví dụ:
streamHTML(),setHTMLUnsafe()) cho phép thiết lập HTML hoặc truyền trực tuyến các luồng có thể đọc trực tiếp vào các phần tử DOM với hiệu suất gốc và thực thi tập lệnh không bắt buộc.
Các phương pháp hay nhất
- Ưu tiên nội dung trong màn hình đầu tiên: Truyền trực tuyến giao diện người dùng quan trọng (tiêu đề, chính, điều hướng chính, nội dung chính) trước tiên. Sử dụng phần giữ chỗ cho các thành phần "tốn kém" hoặc có mức độ ưu tiên thấp hơn như bình luận, quảng cáo hoặc nội dung có liên quan.
- Triển khai trạng thái tải gốc: Sử dụng điểm đánh dấu
<?start>và<?end>để gói nội dung dự phòng. Trình duyệt sẽ tự động thay thế mọi nội dung giữa các điểm đánh dấu này khi<template for>tương ứng đến. - Giảm thiểu Mức thay đổi bố cục tích luỹ (CLS): Luôn cung cấp kích thước ổn định cho phần giữ chỗ. Nếu không biết kích thước nội dung cuối cùng, hãy sử dụng màn hình khung xương hoặc
aspect-ratioCSS để đặt trước không gian và ngăn chặn các thay đổi đột ngột. - Hỗ trợ tiếp cận và quản lý tiêu điểm: Xin lưu ý rằng các bản cập nhật không theo thứ tự có thể gây nhầm lẫn cho người dùng trình đọc màn hình. Sử dụng các vùng
aria-livecho các bản cập nhật quan trọng và đảm bảo rằng tiêu điểm không bị mất nếu phần giữ chỗ chứa phần tử đang hoạt động được thay thế.
Thông tin chi tiết về việc triển khai
1. Điểm đánh dấu HTML khai báo
Trình duyệt tìm các lệnh xử lý cụ thể để xác định vị trí cần vá nội dung.
<!-- 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>
Sau khi <template> thay thế một điểm chèn, điểm chèn đó sẽ không còn tồn tại và không thể sử dụng lại. Tuy nhiên, <template> có thể chứa các điểm chèn có thể dùng sau này trong luồng.
<?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. Truyền trực tuyến JS bắt buộc
Trình duyệt cung cấp một bộ gồm 24 phương thức (6 hành động, mỗi hành động có 4 biến thể) để cập nhật DOM theo cách tĩnh (từ một chuỗi) hoặc thông qua một luồng.
Bảng tham chiếu API
| Hành động | Tĩnh (An toàn) | Phát trực tuyến (An toàn) | Tĩnh (Không an toàn) | Phát trực tuyến (Không an toàn) |
|---|---|---|---|---|
| Set | setHTML() |
streamHTML() |
setHTMLUnsafe() |
streamHTMLUnsafe() |
| Thay thế | replaceWithHTML() |
streamReplaceWithHTML() |
replaceWithHTMLUnsafe() |
streamReplaceWithHTMLUnsafe() |
| Trước | beforeHTML() |
streamBeforeHTML() |
beforeHTMLUnsafe() |
streamBeforeHTMLUnsafe() |
| Thêm vào đầu | prependHTML() |
streamPrependHTML() |
prependHTMLUnsafe() |
streamPrependHTMLUnsafe() |
| Thêm | appendHTML() |
streamAppendHTML() |
appendHTMLUnsafe() |
streamAppendHTMLUnsafe() |
| Sau | afterHTML() |
streamAfterHTML() |
afterHTMLUnsafe() |
streamAfterHTMLUnsafe() |
Khái niệm chính
- An toàn và không an toàn:
- Theo mặc định, các phương thức an toàn (ví dụ:
setHTML()) sử dụng trình dọn dẹp tích hợp để loại bỏ nội dung có khả năng gây nguy hiểm như thẻ<script>. Bạn có thể truyền một đối tượngSanitizertuỳ chỉnh trong các tuỳ chọn để áp dụng ngoài trình dọn dẹp mặc định. - Các phương thức không an toàn (ví dụ:
setHTMLUnsafe()) không dọn dẹp theo mặc định, nhưng bạn vẫn có thể truyềnSanitizertuỳ chỉnh. Để cho phép tập lệnh thực thi trong nội dung mới, bạn phải truyền{ runScripts: true }một cách rõ ràng trong các tuỳ chọn. QUAN TRỌNG: Chỉ sử dụng các phương thức không an toàn với nội dung đáng tin cậy khi các phương thức an toàn không hoạt động.
- Theo mặc định, các phương thức an toàn (ví dụ:
- Tĩnh và Truyền trực tuyến:
- Các phương thức tĩnh lấy một chuỗi (hoặc
TrustedHTML) và áp dụng chuỗi đó ngay lập tức. - Các phương thức Truyền trực tuyến trả về một
WritableStream. Điều này cho phép bạn chuyển nội dung (ví dụ: từ phản hồifetch) trực tiếp vào DOM và trình duyệt sẽ hiển thị nội dung đó dần dần khi các đoạn dữ liệu đến.
- Các phương thức tĩnh lấy một chuỗi (hoặc
Ví dụ: Truyền trực tuyến phản hồi tìm nạp
Bạn có thể chuyển trực tiếp phản hồi tìm nạp vào DOM mà không cần xử lý đoạn dữ liệu theo cách thủ công.
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 }))
Ma trận tham chiếu trường hợp sử dụng
- Kiến trúc đảo: Hydrate các thành phần tương tác độc lập trên HTML tĩnh mà không cần thời gian chạy khung đầy đủ.
- Trì hoãn các khối "tốn kém": Cung cấp ngay khung của trang và truyền trực tuyến các thành phần nặng về cơ sở dữ liệu khi có sẵn.
- Nội dung cập nhật về Ứng dụng trang đơn (SPA): Truyền trực tuyến các hiệu ứng chuyển đổi giao diện người dùng lớn trong SPA bằng
streamHTML()thay vì chờ tải trọng JSON đầy đủ và tạo DOM theo cách thủ công.
Mẫu phản thiết kế và cảnh báo (KHÔNG ĐƯỢC LÀM ĐIỀU NÀY)
- Đừng sử dụng tính năng truyền trực tuyến OOO cho mọi thứ. Việc phân mảnh quá mức một trang có thể làm tăng độ phức tạp của luồng và có khả năng làm chậm nội dung nếu trình duyệt mất quá nhiều thời gian để vá các nút nhỏ.
- Đừng bỏ qua Trusted Types. Khi sử dụng các phương thức
*Unsafetrong môi trường có thực thi Trusted Types, hãy đảm bảo bạn đang truyền một đối tượng chính sách đã dọn dẹp nếu cần. - Đừng giả định thứ tự thực thi tập lệnh. Tập lệnh bên trong
<template for>sẽ thực thi ngay khi được vá vào tài liệu. Đừng dựa vào việc các mẫu này thực thi theo một trình tự cụ thể so với các mẫu trì hoãn khác. - Không sử dụng nếu không có chiến lược polyfill. Hãy đảm bảo bạn có phương án dự phòng hoặc sử dụng polyfill (
html-setters-polyfillvàtemplate-for-polyfill) để hỗ trợ các trình duyệt cần thiết cho đến khi tính năng này trở thành Baseline.
Chiến lược dự phòng
Bạn có thể sử dụng polyfill như template-for-polyfill và html-setters-polyfill để mô phỏng giao diện API cho các trình duyệt không hỗ trợ.
Các trình duyệt không hỗ trợ html-processing-instructions sẽ phân tích cú pháp <?marker>, <?start> và <?end> dưới dạng nhận xét. template-for-polyfill vẫn nhận dạng các nhận xét này dưới dạng điểm đánh dấu, vì vậy, hãy giữ nguyên cú pháp lệnh xử lý cho tất cả trình duyệt. Đừng viết lại các điểm đánh dấu dưới dạng nhận xét hoặc phần tử HTML cho các trình duyệt không hỗ trợ.