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

Gần đây, bạn có 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 kết hợp là một trong những thế mạnh lớn của web, cho phép chúng ta 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 khả năng kết hợp là nó ngụ ý trách nhiệm chia sẻ đối với trải nghiệm người dùng. Nếu quá trình tích hợp không tối ưu, 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 trường hợp 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 gặp một tập lệnh, trình phân tích cú pháp 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 chèn động 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 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 thông qua document.write() có thể làm chậm quá trình hiển thị nội dung trang chính trong vài chục giây, hoặc khiến trang không thể tải hoặc tải quá lâu nên người dùng bỏ cuộc. Dựa trên thông tin đ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 hơn hai lần so với các trang khác trên 2G.

Chúng tôi đã thu thập dữ liệu từ thử nghiệm thực địa 28 ngày trên 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ượt 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 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 đó:

  • 10% số lượt tải trang đạt đến lần vẽ nội dung đầu tiên (một xác nhận trực quan cho người dùng rằng trang đang tải hiệu quả), 25% số lượt tải trang đạt đến trạng thái được phân tích cú pháp đầy đủ và 10% số lượt tải lại ít hơn, cho thấy sự giảm bớt sự khó chịu của người dùng.
  • Giảm 21% thời gian trung bình (nhanh hơn hơn 1 giây) cho đến khi có lần vẽ 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, tương đương với việc cải thiện gần 6 giây, giúp giảm đáng kể thời gian hiển thị 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, sẽ 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 dùng kết nối chậm, cụ thể là khi người dùng đang dùng mạ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 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. Hành động can thiệp này không áp dụng cho các tập lệnh document.written trong iframe vì các tập lệnh này không chặn việc 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. Các tập lệnh có thuộc tính "async" hoặc "defer" sẽ vẫn 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 khớp (ví dụ: một tập lệnh được lưu trữ trên js.example.org được chèn vào 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ị chậm trễ do mạng và vẫn sẽ thực thi.
  6. Yêu cầu về trang này 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 một lượt 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 thay, 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 các tập lệnh của bên thứ ba tải mà không chặn việc hiển thị 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 các 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ử của tập lệnh hoặc thêm các phần tử của tập lệnh bằng API DOM như document.appendChild() hoặc parentNode.insertBefore().

Cách phát hiện thời điểm 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 thời điểm người dùng đang dùng mạ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 hệ thống phân tích hoặc hệ thống Chỉ số người dùng thực (RUM).

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 yêu cầu document.write() đáp ứng các tiêu chí từ 2 đến 5 (Chrome bỏ qua 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.

Việc thấy cảnh báo trong Công cụ cho nhà phát triển Chrome là rất tuyệt, nhưng làm cách nào để 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 biện pháp can thiệp xảy ra.

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 thông 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 phát hiện một tập lệnh được chèn thông 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ó can thiệp thực tế).

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

Kế hoạch ban đầu là thực thi biện pháp can thiệp này khi chúng tôi phát hiện các tiêu chí đang được đáp ứng. Chúng tôi bắt đầu bằng cách chỉ hiển thị cảnh báo trong Bảng điều khiển dành cho nhà phát triển trong Chrome 53. (Giai đoạn thử nghiệm beta là vào tháng 7 năm 2016. Chúng tôi dự kiến sẽ cung cấp phiên bản ổn định 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. Phiên bản này dự kiến sẽ được 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ẽ can thiệp khi bất kỳ người dùng nào có kết nối chậm (tức là 3G hoặc Wi-Fi chậm). Làm theo mục Trạng thái của 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: