Technical SEO

DOMContentLoaded Event

Sự kiện kích hoạt khi cây DOM đã được phân tích xong, không chờ CSS, hình ảnh hay script bên ngoài.

5 lượt xem Cập nhật: 01/06/2026

DOMContentLoaded Event là gì?

DOMContentLoaded là một sự kiện trong trình duyệt, được kích hoạt ngay khi cây DOM (Document Object Model) của trang đã được phân tích xong — tức là trình duyệt đã đọc và xử lý toàn bộ mã HTML, tạo ra cấu trúc cây DOM đầy đủ, nhưng chưa cần đợi các tài nguyên bên ngoài như CSS, hình ảnh, font, script không chặn hiển thị hoặc iframe.

Sự kiện này khác với window.onload, vốn chỉ chạy sau khi tất cả tài nguyên (kể cả hình ảnh, CSS, script đồng bộ) đều tải xong. Vì vậy, DOMContentLoaded thường xảy ra sớm hơn nhiều — thường trong vòng vài chục mili giây sau khi HTML được nhận xong.

Tại sao quan trọng trong SEO?

Với Technical SEO, thời điểm DOM sẵn sàng ảnh hưởng trực tiếp đến khả năng thu thập và hiểu nội dung của công cụ tìm kiếm — đặc biệt là Googlebot. Từ năm 2019, Google xác nhận dùng phiên bản Chromium để render trang, nghĩa là Googlebot cũng tuân theo chu kỳ sự kiện giống trình duyệt Chrome.

Khi JavaScript thay đổi nội dung DOM sau khi trang tải (ví dụ: render động bằng React, Vue hoặc thêm nội dung qua fetch), công cụ tìm kiếm chỉ thu thập được phần nào đó nếu nội dung đó xuất hiện trước hoặc tại thời điểm DOMContentLoaded. Nếu nội dung quan trọng (tiêu đề, mô tả, schema, nội dung chính) chỉ xuất hiện sau sự kiện này — ví dụ do script chạy chậm, bị chặn hoặc phụ thuộc vào API chậm — thì Google có thể bỏ lỡ hoặc đánh giá sai mức độ liên quan.

Ngoài ra, việc tối ưu hóa logic khởi chạy script vào đúng thời điểm DOMContentLoaded giúp giảm thiểu thời gian chờ trước khi nội dung tương tác được — cải thiện Core Web Vitals như INP (Interaction to Next Paint) và hỗ trợ trải nghiệm người dùng trên thiết bị di động.

Cách hoạt động

Trình duyệt xử lý HTML theo thứ tự từ trên xuống dưới:

  1. Phân tích HTML → xây dựng cây DOM
  2. Nếu gặp thẻ <script> không có thuộc tính async hoặc defer, trình duyệt tạm dừng phân tích DOM để tải và thực thi script đó (gọi là parser-blocking)
  3. Nếu gặp <link rel="stylesheet">, trình duyệt không dừng phân tích DOM, nhưng sẽ hoãn DOMContentLoaded cho đến khi CSSOM (CSS Object Model) được xây dựng xong — vì CSS có thể ảnh hưởng đến layout và hiển thị
  4. Khi cây DOM hoàn tất CSSOM sẵn sàng → trình duyệt kích hoạt sự kiện DOMContentLoaded

Lưu ý: Hình ảnh, video, iframe, script có async/defer không ảnh hưởng đến thời điểm DOMContentLoaded.

Hướng dẫn thực hiện

Để tận dụng DOMContentLoaded đúng cách trong bối cảnh SEO, bạn nên:

  1. Đặt script khởi tạo giao diện vào đúng thời điểm: Dùng document.addEventListener('DOMContentLoaded', callback) hoặc viết script ở cuối <body> — đảm bảo DOM đã sẵn sàng trước khi chạy logic thay đổi nội dung.
  2. Tránh chặn parser bằng script không cần thiết: Thay thế <script src="..."></script> ở đầu <head> bằng defer (nếu thứ tự thực thi quan trọng) hoặc async (nếu độc lập).
  3. Không phụ thuộc vào dữ liệu bất đồng bộ quá muộn: Nếu nội dung chính (ví dụ: tiêu đề bài viết, đoạn mở đầu) được lấy từ API, hãy đảm bảo gọi API ngay trong DOMContentLoaded — hoặc tốt hơn: render sẵn trên server (SSR) để nội dung có mặt trong HTML ban đầu.
  4. Kiểm tra thứ tự thực thi: Dùng DevTools → tab Performance → ghi lại tải trang → tìm dấu mốc DOMContentLoaded và so sánh với thời điểm nội dung quan trọng xuất hiện trong cây DOM (tab Elements).

Lỗi thường gặp

  • Script chạy quá sớm: Gọi document.querySelector trước khi DOM sẵn sàng → trả về null. Cách khắc phục: Bao toàn bộ logic trong hàm lắng nghe DOMContentLoaded, hoặc dùng defer cho script ở <head>.
  • DOMContentLoaded bị trì hoãn bởi CSS chậm: Nếu file CSS quá lớn hoặc tải từ miền chậm, trình duyệt phải đợi CSSOM xong mới kích hoạt sự kiện. Cách khắc phục: Tối ưu CSS (inlining critical CSS, loại bỏ CSS thừa, nén, preload CSS quan trọng).
  • Tin tưởng sai vào thời điểm render: Giả sử nội dung JS-rendered luôn có mặt tại DOMContentLoaded, trong khi thực tế nó chỉ xuất hiện sau khi fetch thành công. Cách khắc phục: Kiểm tra bằng Google Search Console → URL Inspection → View tested page để xem nội dung mà Googlebot thấy — nếu thiếu nội dung chính, khả năng cao là do phụ thuộc vào JS chạy sau sự kiện này.

Ví dụ thực tế

Dưới đây là hai cách triển khai phổ biến — một sai, một đúng — với cùng mục tiêu: thêm tiêu đề động vào trang:

Cách làm Mã mẫu Hệ quả với SEO
Sai — Chạy script trước DOM sẵn sàng
<script>
  document.getElementById('title').textContent = 'Bài viết mới';
</script>
<h1 id="title"></h1>
Googlebot thấy thẻ <h1> rỗng → không thu thập được tiêu đề. Nội dung chỉ xuất hiện sau khi script chạy — nhưng script có thể bị bỏ qua hoặc thực thi chậm.
Đúng — Đợi DOM sẵn sàng
<h1 id="title"></h1>
<script>
  document.addEventListener('DOMContentLoaded', () => {
    document.getElementById('title').textContent = 'Bài viết mới';
  });
</script>
DOM đã tồn tại khi script chạy → tiêu đề được gán đúng lúc. Nếu Googlebot render trang, nó sẽ thấy nội dung đầy đủ — tùy trường hợp (phụ thuộc vào tốc độ mạng, độ phức tạp script).

Câu hỏi thường gặp

DOMContentLoaded có xảy ra trên mọi trình duyệt?

Có. Sự kiện này được hỗ trợ đầy đủ trên tất cả trình duyệt hiện đại (Chrome, Firefox, Safari, Edge từ phiên bản 12 trở lên). IE8 trở lên cũng hỗ trợ, nhưng cú pháp khác — tuy nhiên IE không còn được Googlebot hỗ trợ từ năm 2021.

Googlebot có chờ DOMContentLoaded không?

Googlebot không “đợi” sự kiện theo nghĩa chủ động, mà nó render trang theo chu kỳ sự kiện giống Chrome. Khi Googlebot hoàn tất xây dựng DOM và CSSOM, nó coi trang đã “sẵn sàng để tương tác” — và đây là thời điểm nó bắt đầu thu thập nội dung hiển thị. Vì vậy, nội dung xuất hiện tại hoặc trước DOMContentLoaded có tỷ lệ được thu thập cao hơn.

Có nên dùng window.onload thay vì DOMContentLoaded cho SEO?

Không. window.onload xảy ra muộn hơn nhiều — thường sau khi tải xong toàn bộ hình ảnh, iframe, script không defer. Nếu bạn đợi sự kiện này để hiển thị nội dung chính, Googlebot có thể kết luận trang “trống” hoặc “thiếu nội dung”, dẫn đến xếp hạng kém. Chỉ dùng window.onload cho các tác vụ không ảnh hưởng đến nội dung chính (ví dụ: thống kê, lazyload ảnh nền).