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

Gần đây, bạn có thấy một cảnh báo như sau trong Bảng điều khiển dành cho nhà phát triển trên Chrome và thắc mắc về cảnh báo đó 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 kết 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 để 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 về trải nghiệm người dùng. Nếu việc 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 gây ra 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 trang sử dụng tính năng chèn tập lệnh. Vô hại như vẻ ngoài sau đây, nó có thể gây ra những vấn đề thực sự cho người dùng.

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

Trước khi 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 mã đá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, nó phải dừng và thực thi trước khi có thể tiếp tục phân tích cú pháp HTML. Nếu tập lệnh chèn động một tập lệnh khác, trình phân tích cú pháp sẽ buộc phải đợi tải tài nguyên xuống lâu hơn nữa. Điều này có thể khiến trang phải nhận 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ể trì hoãn việc hiển thị nội dung trang chính trong vài chục giây, hoặc khiến trang không tải được hoặc mất 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 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ừ bản dùng thử nội bộ 28 ngày đối với 1% người dùng ổn định của Chrome, giới hạn ở những người dùng kết nối 2G. Chúng tôi nhận thấy 7, 6% tổng số lượt tải trang qua 2G có í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 các điểm cải tiến sau đây đối với các lượt tải đó:

  • Số lượt tải trang tăng 10% đạt đến nội dung đầu tiên (thông tin xác nhận trực quan 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à số lượt tải lại giảm 10% cho thấy mức độ thất vọng của người dùng giảm đi.
  • 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 để phân tích cú pháp một trang, nghĩa là cải thiện được 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 với người dùng.

Với dữ liệu này, Chrome, kể từ phiên bản 55, sẽ can thiệp thay 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 Trạng thái Chrome). Cụ thể là Chrome sẽ không thực thi các phần tử <script> được chèn thông qua document.write() khi đáp ứng tất cả điều kiện sau:

  1. Người dùng sử dụng kết nối chậm, đặc biệt là khi người dùng đang dùng 2G. (Trong tương lai, thay đổi này có thể được mở rộng cho những người dùng khác sử dụng các kết nối chậm, chẳng hạn như 3G chậm hoặc Wi-Fi chậm.)
  2. document.write() nằm trong tài liệu cấp cao nhất. Biện pháp can thiệp này không áp dụng cho tập lệnh document.write trong iframe vì các tập lệnh này không chặn hoạt động hiển thị của 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ẽ 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 trùng khớ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 bị trễ mạng và sẽ vẫn thực thi.
  6. Yêu cầu đối với trang không phải là một lượt 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 bên thứ ba đều cung cấp các phương án tải không đồng bộ, cho phép các tập lệnh bên thứ ba tải mà không chặn hiển thị phần còn lại của nội dung trên trang.

Làm cách nào để khắc phục sự cố này?

Câu trả lời đơn giản này là đừng chèn tập lệnh bằng document.write(). Chúng tôi duy trì một nhóm các dịch vụ đã biết để hỗ trợ trình tải không đồng bộ và 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ợ tính năng tải tập lệnh không đồng bộ 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 cách tập lệnh bị ảnh hưởng.

Nếu nhà cung cấp cung cấp cho bạn một đoạn mã chứa document.write(), thì 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, chẳng hạn như document.appendChild() hoặc parentNode.insertBefore().

Cách phát hiện thời điểm trang web bị ảnh hưởng

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

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

Để hiểu tác động tiềm năng của thay đổi này, trước tiên, bạn cần biết có bao nhiêu người dùng sẽ sử dụng 2G. Bạn có thể phát hiện loại mạng và tốc độ mạng hiện tại của người dùng bằng cách sử dụng Network Information API (API Thông tin mạng) có trong Chrome, sau đó gửi thông báo đến hệ thống phân tích hoặc Hệ thống chỉ số người dùng thực (RSA) 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 những câu lệnh document.write() có vấn đề. Cụ thể, nếu một yêu cầu document.write() đáp ứng các 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), cảnh báo sẽ có dạng như sau:

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

Việc nhận được các cảnh báo trong Công cụ của Chrome cho nhà phát triển thật tuyệt vời, nhưng làm cách nào để bạn phát hiện điều này trên 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 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 được chèn qua document.write bị chặn, Chrome sẽ gửi tiêu đề sau đế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 trong yêu cầu GET cho tập lệnh (không đồng bộ trong trường hợp có sự 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 bằng việc chỉ hiển thị một cảnh báo trong Bảng điều khiển dành cho nhà phát triển trong Chrome 53. (Phiên bản beta đã được triển khai 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 để chặn các tập lệnh được chèn cho người dùng 2G dự kiến bắt đầu từ Chrome 54. Theo dự kiến, phiên bản này sẽ có 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 bất kỳ người dùng nào có kết nối chậm (ví dụ: kết nối 3G hoặc Wi-Fi chậm). Hãy làm theo mục Trạng thái trên 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: