Can thiệp vào document.write()

Gần đây, bạn có nhìn thấy cảnh báo như sau trong Bảng điều khiển dành cho nhà phát triển trong Chrome và thắc mắc đó là cảnh báo gì không?

(index):34 A Parser-blocking, cross-origin script,
https://paul.kinlan.me/ad-inject.js, is invoked via document.write().
This may be blocked by the browser if the device has poor network connectivity.

Khả năng tích hợp là một trong những sức mạnh tuyệt vời của web, cho phép chúng tôi dễ dàng tích hợp với các dịch vụ do bên thứ ba xây dựng nhằm tạo ra các sản phẩm mới tuyệt vời! Một trong những nhược điểm của tính năng kết hợp là nó ngụ ý trách nhiệm chung trong trải nghiệm người dùng. Nếu quy trình tích hợp chưa đạt hiệu quả tối ưu, thì trải nghiệm người dùng sẽ bị ảnh hưởng tiêu cực.

Một nguyên nhân đã biết dẫn đến hiệu suất kém là việc sử dụng document.write() bên trong các trang, cụ thể là những cách sử dụng chèn tập lệnh. Tuy vô hại như sau, nhưng nó có thể gây ra vấn đề thực sự cho người dùng.

document.write('<script src="https://example.com/ad-inject.js"></script>');

Trước khi trình duyệt có thể hiển thị một trang, trình duyệt phải xây dựng cây DOM bằng cách phân tích cú pháp đánh dấu HTML. Bất cứ khi nào trình phân tích cú pháp gặp một tập lệnh, trình phân tích cú pháp sẽ phải dừng và thực thi tập lệnh đó trước khi có thể tiếp tục phân tích cú pháp HTML. Nếu tập lệnh tự động chèn một tập lệnh khác, thì trình phân tích cú pháp sẽ buộc phải đợi lâu hơn nữa để tải tài nguyên xuống. Điều này có thể làm phát sinh một hoặc nhiều lượt trả về mạng và trì hoãn thời gian kết xuất trang lần đầu tiên

Đối với người dùng trên các kết nối chậm, chẳng hạn như 2G, các tập lệnh bên ngoài được chèn động qua document.write() có thể làm chậm việc hiển thị nội dung trang chính trong hàng chục giây hoặc khiến các trang không tải được hoặc mất quá nhiều thời gian đến mức người dùng bỏ cuộc. Dựa trên khả năng đo lường trong Chrome, chúng tôi nhận thấy rằng các trang có tập lệnh của bên thứ ba được chèn qua document.write() thường có tốc độ tải chậm gấp đôi so với các trang khác trên 2G.

Chúng tôi đã thu thập dữ liệu từ hoạt động thử nghiệm thực địa trong 28 ngày đối với 1% người dùng ổn định của Chrome, chỉ dành cho người dùng có kết nối 2G. Chúng tôi nhận thấy 7, 6% tổng số lần tải trang trên 2G bao gồm ít nhất một tập lệnh chặn trình phân tích cú pháp trên nhiều trang web đã được chèn qua document.write() trong tài liệu cấp cao nhất. Do việc chặn tải các tập lệnh này, chúng tôi nhận thấy những điểm cải tiến sau đây đối với các lượt tải đó:

  • Tăng 10% lượt tải trang đạt đến nội dung đầu tiên hiển thị (thông tin xác nhận cho người dùng rằng trang đang tải hiệu quả), thêm 25% lượt tải trang đạt đến trạng thái được phân tích cú pháp đầy đủ và giảm 10% số lần tải lại giúp giảm cảm giác khó chịu cho người dùng.
  • Giảm 21% thời gian trung bình (nhanh hơn một giây) cho đến khi hiển thị nội dung đầu tiên
  • Giảm 38% thời gian trung bình cần thiết để phân tích cú pháp một trang, cải thiện gần 6 giây, giúp giảm đáng kể thời gian cần thiết để hiển thị những nội dung quan trọng đối với người dùng.

Dựa trên dữ liệu này, Chrome, kể từ phiên bản 55, can thiệp thay mặt cho tất cả người dùng khi chúng tôi phát hiện mẫu xấu này bằng cách thay đổi cách xử lý document.write() trong Chrome (Xem phần Trạng thái Chrome). Cụ thể, Chrome sẽ không thực thi các phần tử <script> được chèn qua document.write() khi tất cả điều kiện sau được đáp ứng:

  1. Người dùng đang sử dụng kết nối chậm, đặc biệt là khi người dùng sử dụng 2G. (Trong tương lai, thay đổi này có thể được áp dụng cho những người dùng khác trên các kết nối chậm, chẳng hạn như 3G hoặc Wi-Fi chậm.)
  2. document.write() nằm trong một tài liệu cấp cao nhất. Biện pháp can thiệp này không áp dụng cho các tập lệnh document.writer trong iframe vì chúng không chặn quá trình hiển thị trang chính.
  3. Tập lệnh trong document.write() đang chặn trình phân tích cú pháp. Những tập lệnh có thuộc tính "async" hoặc "defer" vẫn sẽ được thực thi.
  4. Tập lệnh không được lưu trữ trên cùng một trang web. Nói cách khác, Chrome sẽ không can thiệp vào các tập lệnh có eTLD+1 phù hợp (ví dụ: tập lệnh được lưu trữ trên js.example.org được chèn trên www.example.org).
  5. Tập lệnh chưa có trong bộ nhớ đệm HTTP của trình duyệt. Các tập lệnh trong bộ nhớ đệm sẽ không gây trễ mạng và vẫn sẽ thực thi.
  6. Yêu cầu cho trang không phải là tải lại. Chrome sẽ không can thiệp nếu người dùng kích hoạt quá trình tải lại và sẽ thực thi trang như bình thường.

Đôi khi, đoạn mã của bên thứ ba sử dụng document.write() để tải tập lệnh. May mắn là hầu hết các bên thứ ba đều cung cấp các phương án tải không đồng bộ, cho phép tập lệnh bên thứ ba tải mà không chặn việc hiển thị phần nội dung còn lại trên trang.

Làm cách nào để khắc phục lỗi này?

Câu trả lời đơn giản này là không chèn tập lệnh bằng document.write(). Chúng tôi duy trì một nhóm dịch vụ đã biết để hỗ trợ trình tải không đồng bộ mà bạn nên tiếp tục kiểm tra.

Nếu nhà cung cấp của bạn không có trong danh sách và hỗ trợ tải tập lệnh không đồng bộ, vui lòng cho chúng tôi biết để chúng tôi có thể cập nhật trang để trợ giúp tất cả người dùng.

Nếu nhà cung cấp của bạn không hỗ trợ khả năng tải không đồng bộ các tập lệnh vào trang của bạn, thì bạn nên liên hệ với họ và cho chúng tôi và họ biết chúng sẽ bị ảnh hưởng như thế nào.

Nếu nhà cung cấp cung cấp cho bạn một đoạn mã bao gồm document.write(), bạn có thể thêm thuộc tính async vào phần tử tập lệnh hoặc thêm các phần tử tập lệnh bằng API DOM như document.appendChild() hoặc parentNode.insertBefore().

Cách phát hiện khi nào trang web của bạn bị ảnh hưởng

Có một số lượng lớn tiêu chí xác định liệu quy định hạn chế này có được thực thi hay không, vậy làm cách nào để biết liệu bạn có bị ảnh hưởng hay không?

Phát hiện khi người dùng đang sử dụng 2G

Để hiểu được tác động tiềm ẩn của thay đổi này, trước tiên, bạn cần biết được có bao nhiêu người dùng sẽ sử dụng mạng 2G. Bạn có thể phát hiện loại và tốc độ mạng hiện tại của người dùng bằng cách sử dụng API Thông tin mạng có trong Chrome, sau đó gửi thông báo cho các hệ thống phân tích hoặc Chỉ số người dùng thực (RUM) của bạn.

if(navigator.connection &&
    navigator.connection.type === 'cellular' &&
    navigator.connection.downlinkMax <= 0.115) {
    // Notify your service to indicate that you might be affected by this restriction.
}

Phát hiện cảnh báo trong Công cụ của Chrome cho nhà phát triển

Kể từ Chrome 53, Công cụ cho nhà phát triển sẽ đưa ra cảnh báo đối với các câu lệnh document.write() có vấn đề. Cụ thể, nếu một yêu cầu document.write() đáp ứng tiêu chí từ 2 đến 5 (Chrome bỏ qua các tiêu chí kết nối khi gửi cảnh báo này), thì cảnh báo sẽ có dạng như sau:

Cảnh báo ghi tài liệu.

Bạn sẽ thấy rất hữu ích khi xem cảnh báo trong Công cụ của Chrome cho nhà phát triển, nhưng làm cách nào để phát hiện điều này ở quy mô lớn? Bạn có thể kiểm tra các tiêu đề HTTP được gửi đến máy chủ của mình khi có can thiệp.

Kiểm tra tiêu đề HTTP trên tài nguyên tập lệnh

Khi một tập lệnh chèn qua document.write bị chặn, Chrome sẽ gửi tiêu đề sau đây đến tài nguyên được yêu cầu:

Intervention: <https://shorturl/relevant/spec>;

Khi tìm thấy một tập lệnh được chèn qua document.write và có thể bị chặn trong nhiều trường hợp, Chrome có thể gửi:

Intervention: <https://shorturl/relevant/spec>; level="warning"

Tiêu đề can thiệp sẽ được gửi như một phần của yêu cầu GET cho tập lệnh (không đồng bộ trong trường hợp có biện pháp can thiệp thực tế).

Tương lai nắm giữ điều gì?

Kế hoạch ban đầu là thực hiện biện pháp can thiệp này khi chúng tôi phát hiện thấy các tiêu chí được đáp ứng. Chúng tôi bắt đầu với việc chỉ hiển thị một cảnh báo trong Developer Console trong Chrome 53. (Phiên bản thử nghiệm beta diễn ra vào tháng 7 năm 2016. Chúng tôi dự kiến phiên bản ổn định sẽ được cung cấp cho tất cả người dùng vào tháng 9 năm 2016.)

Chúng tôi sẽ can thiệp để tạm thời chặn các tập lệnh được chèn cho người dùng 2G kể từ Chrome 54. Phiên bản này dự kiến sẽ có trong một bản phát hành ổn định cho tất cả người dùng vào giữa tháng 10 năm 2016. Hãy xem mục Trạng thái của Chrome để biết thêm thông tin cập nhật.

Theo thời gian, chúng tôi sẽ tìm cách can thiệp khi có bất kỳ người dùng nào dùng kết nối chậm (ví dụ: 3G hoặc Wi-Fi chậm). Làm theo mục Trạng thái Chrome này.

Bạn muốn tìm hiểu thêm?

Để tìm hiểu thêm, hãy xem các tài nguyên bổ sung sau: