Bản cập nhật một phần mang tính khai báo

Xuất bản: Ngày 19 tháng 5 năm 2026

Từ lâu, web đã không còn là phương tiện tĩnh, dựa trên tài liệu như lúc ban đầu. Mọi người đều sử dụng các ứng dụng web hiện đại, đa dạng vì nhiều lý do, từ giao tiếp, mua hàng, sử dụng nội dung đa dạng thức cho đến quản lý cuộc sống phức tạp của chúng ta.

Mặc dù có nhiều tiến bộ, nhưng HTML vẫn được phân phối theo thứ tự từ trên xuống dưới mà ít quan tâm đến thời điểm nội dung sẵn sàng hoặc thời điểm người dùng sử dụng nội dung đó. CSS cho phép bạn thay đổi thứ tự nội dung, nhưng thường có tác dụng phụ đáng kể đối với khả năng tiếp cận. JavaScript cho phép bạn thao tác với DOM thông qua nhiều API để thoát khỏi điều này, nhưng những API đó thường yêu cầu cú pháp chi tiết hoặc cấu trúc của cây DOM để cắm vào HTML.

Hiệu suất là yếu tố cực kỳ quan trọng đối với web, xét đến bản chất máy chủ-ứng dụng của phương tiện này, nhưng thường có những lựa chọn không tối ưu để tránh bản chất theo thứ tự này của HTML, điều này làm giảm hiệu suất. Điều này bao gồm việc chờ cho đến khi toàn bộ trang sẵn sàng hoặc sử dụng một khung hình lớn để phân phối các thành phần theo cách không đồng bộ. Mức độ phổ biến của các khung JavaScript cho thấy rằng nhà phát triển web thích mô hình dựa trên thành phần hơn là mô hình tinh thần tài liệu cứng nhắc về nguồn gốc của web.

Nhóm Chrome đã cân nhắc vấn đề này và đang phát triển các bổ sung mới cho nền tảng web với tên gọi Bản cập nhật một phần mang tính khai báo.

Hai nhóm API mới giúp bạn dễ dàng phân phối HTML theo cách ít tuyến tính hơn, cho dù là theo thứ tự bất kỳ trong chính tài liệu HTML hay thông qua những cách dễ dàng hơn để chèn HTML một cách linh hoạt vào các tài liệu hiện có bằng cách sử dụng các API JavaScript mới. Các tính năng này đã sẵn sàng để nhà phát triển kiểm thử từ Chrome 148 bằng cách sử dụng cờ chrome://flags/#enable-experimental-web-platform-features. Các polyfill cũng có sẵn để cho phép bạn sử dụng ngay những API mới này, ngay cả trong những trình duyệt chưa hỗ trợ các API này.

Những điểm bổ sung này cho nền tảng web đang được chuẩn hoá và nhận được phản hồi tích cực từ các nhà cung cấp trình duyệt khác cũng như các kênh chuẩn hoá. Các tiêu chuẩn có liên quan đang trong quá trình cập nhật để đưa các API mới này vào.

Phát trực tuyến không theo thứ tự

Nhóm thay đổi đầu tiên là các API truyền phát trực tiếp không theo thứ tự mới bằng cách sử dụng phần tử HTML <template> và các phần giữ chỗ chỉ dẫn xử lý. Ví dụ:

<div>
  <?marker name="placeholder">
</div>

...

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

Hướng dẫn xử lý đã tồn tại trong XML từ lâu, nhưng được coi là nhận xét trong HTML và bị bỏ qua. API mới này thay đổi điều đó và đưa chỉ thị xử lý vào HTML. Khi thấy chỉ dẫn xử lý <?marker name="placeholder">, trình duyệt sẽ không làm gì ngay lập tức (giống như trước đây), nhưng bạn có thể tham chiếu các chỉ dẫn này sau.

Phần tử <template> sẽ tra cứu các chỉ dẫn xử lý tương ứng bằng thuộc tính name và thay thế nội dung. Trong trường hợp này, sau khi được phân tích cú pháp, DOM sẽ có dạng:

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

Ngoài thuộc tính <?marker> để thay thế, còn có các dấu hiệu phạm vi <?start><?end> cho phép nội dung giữ chỗ tạm thời xuất hiện trước khi mẫu được xử lý:

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

...

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

Trong trường hợp này, Loading… sẽ xuất hiện cho đến khi <template> xuất hiện, sau đó Loading… sẽ được thay thế bằng nội dung mới.

Bạn cũng có thể thêm chỉ dẫn xử lý vào mẫu để cho phép nhiều bản cập nhật:

<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>
...

Sau khi được phân tích cú pháp, HTML này sẽ có dạng như sau:

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

Với chỉ dẫn xử lý cuối cùng ở cuối trong trường hợp có thêm <template for="results"> vào tài liệu sau này.

Bản minh hoạ

Trong video này, một ứng dụng cơ bản về album ảnh được triển khai bằng HTML truyền trực tuyến:

Bản minh hoạ album ảnh được triển khai bằng tính năng phát trực tuyến không theo thứ tự (nguồn)

Cả trạng thái và ảnh đều được truyền vào HTML sau bố cục ban đầu.

Trường hợp sử dụng

Có nhiều trường hợp sử dụng cho HTML vá lỗi không theo thứ tự này khi kết hợp với HTML truyền trực tuyến:

  • Kiến trúc đảo. Một mẫu phổ biến được các khung như Astro kiến trúc đảo phổ biến, trong đó các thành phần được truyền dữ liệu một cách độc lập trên đầu trang HTML tĩnh. API <template for> cho phép xử lý nội dung tĩnh theo cách tương tự ngay trong HTML. Các khung JavaScript cũng có thể sử dụng tính năng này cho các phần tử tương tác hơn hoặc để xử lý các thành phần.
  • Phân phối nội dung khi đã sẵn sàng. Nhờ cấu trúc đảo này, nội dung có thể được truyền trực tuyến khi đã sẵn sàng thay vì bị giữ lại cho nội dung cần xử lý thêm, chẳng hạn như tra cứu cơ sở dữ liệu. Mặc dù nhiều nền tảng cho phép truyền trực tuyến HTML, nhưng bản chất theo thứ tự của HTML có nghĩa là nội dung thường bị giữ lại hoặc bằng cách sử dụng các thao tác DOM JavaScript phức tạp. Giờ đây, bạn có thể phân phối nội dung tĩnh trong khi chờ đợi, sau đó cắm nội dung đắt tiền hơn vào cuối luồng HTML.
  • HTML có thể được phân phối theo thứ tự tối ưu để có hiệu suất tải trang. Nếu đi sâu hơn, bạn có thể thay đổi thứ tự ngay cả khi đã sẵn sàng. Ví dụ: trình đơn lớn là một tính năng điều hướng phổ biến chứa nhiều HTML mà người dùng sẽ không thấy cho đến khi trang trở nên có tính tương tác. Phần lớn HTML này có thể được phân phối sau trong tài liệu HTML để ưu tiên HTML quan trọng hơn cần thiết cho lần tải trang ban đầu. Thứ tự không còn là rào cản với HTML nữa.

Đây chỉ là một số trường hợp sử dụng và chúng tôi rất mong chờ xem các nhà phát triển sẽ sử dụng API mới này cho mục đích gì.

Các quy định hạn chế và điểm tinh tế

API này có một số hạn chế và điểm tinh tế cần lưu ý:

  • <template for> chỉ có thể cập nhật các chỉ thị xử lý trong cùng một phần tử mẹ vì lý do bảo mật. Việc thêm <template for> trực tiếp vào phần tử <body> sẽ cấp cho phần tử này quyền truy cập vào toàn bộ tài liệu (bao gồm cả <head>).
  • Chỉ thị xử lý <?end> là không bắt buộc và nếu thiếu, nội dung giữa phần tử <?start> và phần cuối của phần tử chứa sẽ được thay thế.
  • Việc di chuyển chỉ thị xử lý sau khi <template for> bắt đầu truyền phát trực tiếp cũng có thể gây ra những hậu quả không mong muốn khi nội dung mới tiếp tục truyền phát trực tiếp vào vị trí cũ.
  • Xin lưu ý rằng khi chèn <template for> một cách linh động bằng phương thức như setHTML hoặc innerHTML, "thư mục mẹ" của mẫu khi được phân tích cú pháp là một đoạn tài liệu trung gian. Điều đó có nghĩa là việc chèn HTML bằng các phương thức này không thể sửa đổi DOM hiện có và việc vá lỗi xảy ra "tại chỗ" bên trong mảnh. Tuy nhiên, khi phát trực tuyến bằng các phương thức như streamHTMLUnsafe (chúng ta sắp đề cập!), sẽ không có đoạn trung gian nên các mẫu có thể thay thế nội dung hiện có.

Các điểm bổ sung tiềm năng trong tương lai

Một số tính năng tiềm năng có thể được bổ sung trong tương lai đang được cân nhắc, bao gồm:

  • Bao gồm phía máy khách. Ví dụ: <template for="footer" patchsrc="/partials/footer.html">.
  • Gộp nhóm. Phía máy khách, các thành phần kết hợp của mảnh cũng có thể được mở rộng để xử lý việc phân lô nhằm đảm bảo nhiều bản cập nhật xảy ra cùng một lúc.
  • Ngăn chặn việc ghi đè nội dung không thay đổi. Bạn có thể đạt được điều này bằng số phiên bản hoặc phiên bản nội dung. Điều này sẽ cho phép duy trì trạng thái giữa các lần thay đổi tuyến đường hoặc các bản cập nhật khác thay vì đặt lại nội dung.
  • Dọn dẹp trong khi vá. Ví dụ: <template for=icon safe><svg id="from-untrusted-source">...</svg></template>

Polyfill

Nhóm Chrome đã phát hành một template-for-polyfill có trên npm để cho phép các trang web sử dụng ngay chức năng mới này, ngay cả trước khi chức năng này xuất hiện trong các trình duyệt khác.

Có một số hạn chế vì không thể cập nhật trực tiếp trình phân tích cú pháp HTML của trình duyệt, nhưng các trường hợp sử dụng phổ biến nhất đều được đề cập. Các trang web vẫn nên thử nghiệm trong các trình duyệt khác.

Phương thức chèn và phát trực tuyến HTML mới

Không phải nội dung nào cũng có thể được gửi ở định dạng HTML. Một phần khác trong công việc mà Chrome đang thực hiện trong lĩnh vực này là giúp bạn dễ dàng cập nhật nội dung thông qua JavaScript.

Đã có nhiều cách để chèn HTML một cách linh hoạt vào một tài liệu hiện có bằng JavaScript:

  • setHTML
  • setHTMLUnsafe
  • Phương thức setter innerHTMLouterHTML
  • createContextualFragment
  • insertAdjacentHTML

Tuy nhiên, tất cả đều hoạt động theo những cách khác nhau một chút với những điểm tinh tế và khác biệt mà nhà phát triển có thể không phải lúc nào cũng cân nhắc:

  • Nội dung mới sẽ ghi đè hay nối thêm?
  • Họ có dọn dẹp HTML có khả năng gây nguy hiểm bằng cách thoát thẻ <script> hay không?
  • Nếu không, <script> có nên chạy không?
  • Các API này hoạt động như thế nào với Trusted Types?

Rất ít nhà phát triển có thể thành thật xem xét những API đó và tự tin trả lời những câu hỏi đó cho từng API.

Một hạn chế lớn là bạn chỉ có thể dùng các đối tượng này cho một bộ HTML hoàn chỉnh đã biết trước, khi có các lệnh gọi cho phép truyền trực tuyến HTML. Trên thực tế, điều này có nghĩa là bạn cần tải toàn bộ nội dung xuống trước khi chèn nội dung đó, trong khi một trong những điểm mạnh của HTML là khả năng phát trực tuyến nội dung ngay lập tức. Bạn có thể giải quyết vấn đề này ở mức độ hạn chế bằng cách chia nhỏ tải trọng hoặc sử dụng các phương thức lỗi thời, không chính thống như document.write, nhưng những phương thức này lại gây ra các vấn đề riêng.

Một bộ API tĩnh và API truyền phát trực tiếp mới

Chrome đã đề xuất một bộ API mới và các tiện ích cho setHTMLsetHTMLUnsafe hiện có để dọn dẹp, cũng như giới thiệu chức năng phát trực tuyến:

Có các phương thức để đặt hoặc thay thế cùng với các phương thức để chèn nội dung trước hoặc sau HTML hiện có. Mỗi phương thức đều có các phương thức tương đương về luồng:

Hành động Tĩnh Phát trực tiếp
Đặt nội dung HTML của phần tử setHTML(html, options); streamHTML(options);
Thay thế toàn bộ phần tử bằng HTML này replaceWithHTML(html, options); streamReplaceWithHTML(options);
Thêm HTML trước phần tử beforeHTML(html, options); streamBeforeHTML(options);
Thêm HTML làm phần tử con đầu tiên của phần tử prependHTML(html, options); streamPrependHTML(options);
Thêm HTML làm phần tử con cuối cùng của phần tử appendHTML(html, options); streamAppendHTML(options);
Thêm HTML sau phần tử afterHTML(html, options); streamAfterHTML(options);
Phương thức chèn và phát trực tuyến mới

Ngoài ra, chúng tôi cũng sẽ đề cập đến các phiên bản Unsafe ngay sau đây. Mặc dù có vẻ như có rất nhiều (đặc biệt là khi bạn thêm các thành phần tương đương Unsafe), nhưng quy ước đặt tên nhất quán giúp bạn dễ dàng nhận biết chức năng của từng thành phần hơn so với các phương thức không liên quan đã đề cập trước đó.

Các phiên bản tĩnh lấy HTML mới làm đối số DOM String, cùng với các lựa chọn không bắt buộc:

const newHTML = "<p>This is a new paragraph</p>";
const contentElement = document.querySelector('#content-to-update');

contentElement.setHTML(newHTML);

Các phiên bản truyền phát trực tiếp hoạt động với Streams API, chẳng hạn như với 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();

Hoặc, thay vào đó, từ một phản hồi tìm nạp, với chuỗi đường ống:

const contentElement = document.querySelector('#content-to-update');

const response = await fetch('/api/content.html');

response.body
  .pipeThrough(new TextDecoderStream())
  .pipeTo(contentElement.streamHTMLUnsafe());

Chúng tôi cũng dự định thêm một phương thức thuận tiện để bạn có thể phát trực tiếp mà không cần bước TextDecoderStream() trung gian.

Đối số options cho phép bạn chỉ định một sanitizer tuỳ chỉnh, mặc định là default, tức là cấu hình trình dọn dẹp mặc định. Cách sử dụng như sau:

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});

Phương thức "Không an toàn"

Ngoài ra, còn có các phiên bản "không an toàn" của từng API:

Hành động Tĩnh Phát trực tiếp
Đặt nội dung HTML của phần tử setHTMLUnsafe(html,options); streamHTMLUnsafe(options);
Thay thế toàn bộ phần tử bằng HTML này replaceWithHTMLUnsafe(html, options); streamReplaceWithHTMLUnsafe(options);
Thêm HTML trước phần tử beforeHTMLUnsafe(html, options); streamBeforeHTMLUnsafe(options);
Thêm HTML làm phần tử con đầu tiên của phần tử prependHTMLUnsafe(html, options); streamPrependHTMLUnsafe(options);
Thêm HTML làm phần tử con cuối cùng của phần tử appendHTMLUnsafe(html, options); streamAppendHTMLUnsafe(options);
Thêm HTML sau phần tử afterHTMLUnsafe(html, options); streamAfterHTMLUnsafe(options);
Các phương thức chèn và phát trực tuyến "không an toàn"

Theo mặc định, các phương thức "không an toàn" này sẽ tắt trình dọn dẹp (bạn có thể chỉ định một trình dọn dẹp tuỳ chỉnh nếu muốn) và cũng cho phép chạy tập lệnh bằng tuỳ chọn runScripts (mặc định là false).

Giống như setHTML, setHTMLUnsafe là một phương thức hiện có, nhưng tham số runScripts options đã được thêm vào phương thức này để cho phép sử dụng phương thức này với việc thực thi tập lệnh:

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});

Từ "không an toàn" trong phương thức này là để nhắc nhở nhà phát triển về nguy cơ tiềm ẩn và cách họ có thể muốn dọn dẹp hoặc hạn chế tập lệnh, chứ không phải để nói rằng không nên sử dụng các phương thức này.

Mức độ "không an toàn" của việc này phụ thuộc vào mức độ tin cậy của dữ liệu đầu vào. Tất cả các phương thức tĩnh Unsafe đều hoạt động với cả DOM String hoặc TrustedHTML làm đối số html và cũng cho phép sử dụng trình dọn dẹp. Mặc dù với runScript, toàn bộ ý định là cho phép tập lệnh, do đó theo mặc định, không có trình dọn dẹp nào được sử dụng.

Trường hợp sử dụng

Các API mới này giúp nhà phát triển dễ dàng thêm HTML vào các trang hiện có, đồng thời thêm các API mới có tên và lựa chọn nhất quán. Các API truyền phát trực tuyến mang lại lợi ích về hiệu suất vì bạn không phải đợi cho đến khi tất cả nội dung mới có trên nền tảng.

Các trường hợp sử dụng bao gồm:

  • Truyền phát trực tiếp linh hoạt các nội dung cập nhật lớn trong Ứng dụng một trang. Như đã đề cập trước đó, một nhược điểm lớn của SPA hiện tại là chúng không thể tận dụng lợi ích từ bản chất truyền trực tuyến của các lần tải HTML ban đầu – cho đến nay!
  • Chèn nội dung phổ biến như chân trang HTML. Việc sử dụng các API JavaScript cho phép bạn kéo các thành phần và chèn chúng vào trang, tận dụng bộ nhớ đệm thay vì lặp lại chúng trong mọi trang được gửi. Tuy nhiên, do phụ thuộc vào JavaScript để chạy, nên bạn chỉ nên sử dụng phương thức này cho nội dung sẽ không xuất hiện trong lần tải ban đầu.

Một lần nữa, đây chỉ là một vài ví dụ và chúng tôi rất mong chờ được xem những gì các bạn sáng tạo!

Các quy định hạn chế và điểm tinh tế

Những API mới này cũng có một số điểm hạn chế và điểm tinh tế mà bạn cần lưu ý:

  • Việc tích hợp tính năng phát trực tuyến với Trusted Types API yêu cầu sử dụng một phương thức createParserOptions mới cho phép chèn một trình dọn dẹp vào mọi thao tác cài đặt HTML. Hãy xem phần giải thích để biết thêm thông tin về việc tích hợp các loại đáng tin cậy
  • Tương tự như <template for>, việc di chuyển các phần tử đang được truyền phát vào có thể gây ra hậu quả không mong muốn hoặc lỗi truyền phát.
  • streamHTMLUnsafe hoạt động giống như trình phân tích cú pháp chính theo nhiều cách, bao gồm cả việc xử lý các chỉ dẫn <template for> khi chúng được thêm vào tài liệu chính và trì hoãn các tập lệnh defer cho đến cuối luồng.

Polyfill

Nhóm Chrome đã phát hành một html-setters-polyfill có trên npm để cho phép các trang web sử dụng ngay chức năng mới này, ngay cả trước khi chức năng này xuất hiện trong các trình duyệt khác.

Xin lưu ý rằng polyfill này không truyền trực tuyến mà sẽ đệm và áp dụng khi hoàn tất. Đây là một polyfill cho hình dạng API hơn là cho chức năng.

Ngoài ra, việc thiết lập nội dung an toàn phụ thuộc vào setHTMLSanitizer API (không được hỗ trợ trong Safari).

Kết hợp cả hai

Mặc dù đây là 2 API riêng biệt, nhưng sức mạnh thực sự đến từ việc kết hợp chúng. Bằng cách truyền trực tuyến các phần tử <template for> mới vào HTML, bạn có thể cập nhật linh hoạt các phần nội dung mà không cần nhắm đến từng phần bằng các tham chiếu JavaScript riêng biệt đến DOM.

Bạn có thể triển khai một lượt tải trang theo kiểu SPA cơ bản bằng cách tải một trang bố cục có hướng dẫn xử lý, sau đó truyền trực tuyến các mẫu của từng trang mới vào cuối HTML để đưa vào các hướng dẫn xử lý đó.

Chắc chắn là cả hai API này đều có nhiều tiềm năng và trường hợp sử dụng hơn, vì vậy, đừng để trí tưởng tượng (dù có hạn!) của chúng tôi cản trở bạn. Bằng cách giúp quản lý các bản cập nhật một phần dễ dàng hơn, bạn có thể giảm bớt một số mã nguyên mẫu, giúp cập nhật dễ dàng hơn và mở ra tiềm năng mới cho web!