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, Lần cập nhật gần đây nhất: ngày 8 tháng 9 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 nội dung vì nhiều lý do, từ giao tiếp, mua hàng, sử dụng nội dung đa dạng 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 tình trạng này, nhưng những API đó thường yêu cầu cú pháp dài dòng hoặc cấu trúc của cây DOM để cắm vào HTML.

Hiệu suất là yếu tố vô cùng quan trọng đối với web, xét đến bản chất máy chủ-máy khách của phương tiện này. Tuy nhiên, các lựa chọn không tối ưu thường được đưa ra để tránh bản chất theo thứ tự này của HTML, điều này làm chậ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 tính năng 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 đầu tiên giúp việc phân phối HTML trở nên dễ dàng hơn 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 các 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 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.

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

Browser Support

  • Chrome: 150.
  • Edge: 150.
  • Firefox: not supported.
  • Safari: not supported.

Source

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

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

...

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

Hướng dẫn xử lý đã có 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 sẽ thay đổi điều đó và đưa chỉ thị xử lý vào HTML. Ví dụ: khi thấy chỉ thị xử lý <?marker name="placeholder">, trình duyệt sẽ không làm gì ngay lập tức (tương tự như trước đây), nhưng chỉ thị này có thể được tham chiếu sau.

Phần tử <template>thuộc tính for 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 như sau (bỏ qua một số khác biệt về khoảng trắng):

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

Ngoài thuộc tính <?marker> để thay thế, còn có các điểm đánh dấ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, chuỗi Loading… sẽ hiển thị cho đến khi <template> xuất hiện, sau đó sẽ được thay thế bằng nội dung mới.

Bạn cũng có thể thêm chỉ thị xử lý vào các 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 và xử lý, 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 các phần giữ chỗ <template for="results"> được thêm vào tài liệu sau này.

Tại sao lại dùng lệnh xử lý thay vì các phần tử HTML tiêu chuẩn?

Đây là câu hỏi thường gặp đối với những người mới sử dụng API này lần đầu, kèm theo đề xuất sử dụng chính các phần tử <slot> hoặc thậm chí là <template>. Phiên bản ban đầu của đề xuất này hoạt động với các phần tử HTML tiêu chuẩn, nhưng các chỉ dẫn xử lý đã được chuyển sang khi thiết kế được lặp lại. Các chỉ thị xử lý cho phép vá lỗi mà không ảnh hưởng đến DOM. Điều này cho phép sử dụng trong <head> (ví dụ: cho các bản cập nhật <title>) hoặc thậm chí bên trong các phần tử khác như <table> (ví dụ: để thêm các hàng bổ sung không bắt buộc).

Mặc dù nhiều nhà phát triển web không quen thuộc với cú pháp này, nhưng chỉ thị xử lý mang lại tính linh hoạt cao hơn nhiều và ít có khả năng gặp phải vấn đề về khả năng tương thích ngược. Chúng đã được dùng trong XML và hiện là một phần của tiêu chuẩn HTML nhờ đề xuất 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 truyền phát trực tiếp 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 dạng đả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 độ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 thành phần 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 (ví dụ: 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 tuần tự của HTML có nghĩa là nội dung thường bị giữ lại hoặc phải dùng đến 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 động và tốn kém 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 danh sách đã 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 vui khi thấy nhà phát triển sử dụng API mới này cho những 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>).
  • Lệnh xử lý <?end> là không bắt buộc và nếu bị 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 một phương thức như setHTML hoặc thuộc tính 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 diễn 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 (sẽ đề cập sau), sẽ không có mảnh trung gian, vì vậy, các mẫu có thể thay thế nội dung hiện có.

Trạng thái chuẩn hoá

Thuộc tính <template for>một phần của tiêu chuẩn HTML nhưng chưa được hỗ trợ trong tất cả các trình duyệt.

Những điểm bổ sung tiềm năng trong tương lai

Một số tính năng tiềm năng khác đang được cân nhắc bổ sung trong tương lai:

  • Bao gồm phía máy khách. Ví dụ: <template for="footer" src="/partials/footer.html"> hoặc thậm chí không cần vá <template src="/partials/footer.html">. Để biết thêm chi tiết, hãy xem video giải thích. Tính năng này có sẵn sau cờ chrome://flags/#enable-experimental-web-platform-features.
  • Ngăn chặn việc ghi đè nội dung sẽ không thay đổi. Bạn có thể đạt được điều này bằng số phiên bản hoặc tính năng kiểm soát phiên bản của 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 kiểm thử 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 phân phối dưới dạng HTML. Một phần khác trong công việc mà Chrome đã thực hiện trong lĩnh vực này là nhằm giúp bạn dễ dàng cập nhật nội dung bằng JavaScript.

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

  • setHTML
  • setHTMLUnsafe
  • innerHTMLouterHTML
  • createContextualFragment
  • insertAdjacentHTML

Tuy nhiên, tất cả đều hoạt động theo những cách hơi khác nhau 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 có ghi đè hay nối thêm vào nội dung cũ không?
  • Họ có dọn dẹp HTML có khả năng gây nguy hiểm không, ví dụ: bằng cách thoát thẻ <script>?
  • Nếu không, có nên chạy <script> không?
  • Chúng hoạt động như thế nào với Trusted Types?

Rất ít nhà phát triển có thể xem xét một cách trung thực 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ể sử 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

Browser Support

  • Chrome: behind a flag.
  • Edge: behind a flag.
  • Firefox: not supported.
  • Safari: not supported.

Chrome đã phát triển 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 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 và dự kiến sẽ ra mắt trong Chrome 155.

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 trong thời gian tới. Mặc dù có vẻ như có rất nhiều thành phần (đặ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 tuyến 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 bằng cách sử dụng chuỗi lệnh pipe:

const contentElement = document.querySelector('#content-to-update');
const response = await fetch('/api/content.html');

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

Phương thức thuận tiện textStream()

Browser Support

  • Chrome: 151.
  • Edge: 151.
  • Firefox: not supported.
  • Safari: not supported.

Chúng tôi cũng đã thêm một phương thức tiện lợi textStream, trong đó bạn có thể phát trực tiếp mà không cần bước TextDecoderStream() trung gian:

const contentElement = document.querySelector('#content-to-update');
const response = await fetch('/api/content.html');

response.textStream().pipeTo(contentElement.streamHTMLUnsafe());

options

Đố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 và bạn có thể chỉ định một trình dọn dẹp tuỳ chỉnh nếu muốn. Các phương thức này cũng cho phép chạy tập lệnh bằng tuỳ chọn runScripts (không bắt buộc) – theo 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 quá trình 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ế các 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 tiếp 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 động 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 cấu trúc SPA hiện tại là nó không tận dụng được 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ờ xem những gì các bạn tạo ra!

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ố 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 video 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 trực tuyến vào có thể gây ra hậu quả không mong muốn hoặc lỗi truyền trực tuyến.
  • 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.

Trạng thái chuẩn hoá

Các phương thức chèn và phát trực tuyến mới hơn đang trong quá trình được thêm vào tiêu chuẩn HTML, nhưng chưa được hỗ trợ trong tất cả các trình duyệt.

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à hai 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 riêng biệt của JavaScript đế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 phác thảo 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 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 bạn dễ dàng quản lý các bản cập nhật một phần, bạn có thể giảm bớt một số mã nguyên mẫu, giúp việc cập nhật trở nên dễ dàng hơn và mở ra tiềm năng mới cho web!

Chrome đang phát triển thêm một số API trong dự án Cập nhật một phần theo khai báo, nhưng chúng tôi rất vui khi cung cấp cho bạn 2 API đầu tiên này. Chúng tôi sẽ thông báo cho bạn khi có thêm thông tin về vấn đề này.