Trong lượng JavaScript trên trang di động trung vị của Web Almanac 2024, 168 kilobyte là của bên thứ nhất và 375 kilobyte là của bên thứ ba.1 Hơn một nửa lượng script trên một trang bình thường, tính theo dung lượng, được viết bởi người khác chứ không phải chủ sở hữu trang web. Chương về bên thứ ba của Almanac cho thấy chúng có mặt trên 92 phần trăm các trang, với script là loại yêu cầu bên thứ ba phổ biến nhất.2 Script của một mạng lưới quảng cáo, thứ mà nhà xuất bản thêm vào để hiển thị quảng cáo, là một trong những yêu cầu đó. Script đó tốn bao nhiêu cho trang lúc tải phụ thuộc ít vào việc nó làm gì hơn là vào cách viết phần tử tải nó.

Trình duyệt dừng lại với một phần tử script không mang thuộc tính nào

Theo Tiêu chuẩn Sống HTML (HTML Living Standard), trình duyệt có ba cách xử lý một script bên ngoài, và chúng chỉ khác nhau ở một thuộc tính trên phần tử.3 Cách thứ nhất, không có thuộc tính nào, là mặc định: script “được tải về và thực thi ngay lập tức, chặn việc phân tích cú pháp cho đến khi cả hai hoàn tất.” Cách thứ hai, defer, tải tệp song song với việc phân tích cú pháp và thực thi nó “khi trang đã phân tích cú pháp xong.” Với cách thứ ba, async, tệp cũng được tải song song nhưng được thực thi “ngay khi có sẵn (có thể trước khi phân tích cú pháp hoàn tất).” Chỉ chế độ thứ nhất giữ trình phân tích cú pháp lại trong khi tệp đi qua mạng, và không gì sau phần tử được vẽ ra cho đến khi tệp đến nơi.

Công cụ kiểm tra Lighthouse của Google biến sự phân biệt này thành một phép thử mà nhà xuất bản có thể chạy trên chính trang của mình. Nó gắn cờ cho phần tử script trong phần head của tài liệu không mang defer lẫn async.4 Báo cáo “liệt kê tất cả các URL đang chặn lần vẽ đầu tiên của trang bạn.” Kích thước không phải là một phần của định nghĩa đó, và mục đích cũng vậy. Một script phân tích, một script quảng cáo và một trình tải phông chữ được đối xử như nhau nếu chúng nằm trong head mà không có thuộc tính.

Script của bên thứ ba là trường hợp mà hướng dẫn về việc tải được viết ra để xử lý

Hướng dẫn trên web.dev nói thẳng về các script từ bên ngoài trang web. Hướng dẫn nói rằng các script đồng bộ “làm chậm việc xây dựng DOM và hiển thị,” DOM là mô hình làm việc của trình duyệt về tài liệu.5 Quy tắc rút ra là “luôn tải script của bên thứ ba một cách bất đồng bộ trừ khi script đó phải chạy trước khi trang có thể được hiển thị.” Async phù hợp với script phải chạy sớm trong quá trình tải; defer phù hợp với “các tài nguyên ít quan trọng hơn,” với ví dụ là một trình phát video bên dưới phần màn hình đầu tiên. Theo phép thử đó, một script quảng cáo hoạt động sau khi văn bản đã hiện trên màn hình thuộc nhóm ít quan trọng hơn.

Cách làm này đã lan rộng, dù chưa đến mọi trang. Web Almanac 2024 cho thấy async có trên 87 phần trăm các trang, tăng từ 76 phần trăm năm 2022, và defer trên 47 phần trăm, tăng từ 42 phần trăm.1 Những con số đó mô tả các trang nói chung. Một trang có các script riêng đã được trì hoãn vẫn có thể chứa một phần tử gây chặn do bên thứ ba cung cấp. Một đoạn mã cài đặt, trừ khi nhà xuất bản chỉnh sửa nó, sẽ tải theo cách mà mạng lưới đã viết.

Một script chờ DOM thì không có lần vẽ đầu tiên nào để chặn

Trình duyệt đánh dấu thời điểm trình phân tích cú pháp xây dựng xong DOM bằng một sự kiện. Theo MDN, DOMContentLoaded “được kích hoạt khi tài liệu HTML đã được phân tích cú pháp hoàn toàn, và tất cả các script trì hoãn” đã được tải về và thực thi.6 Sự kiện này không chờ hình ảnh, khung con hay script async. Do đó một script bắt đầu làm việc tại thời điểm đó sẽ khởi động sau khi văn bản đã tồn tại, mà không cần chờ hình ảnh cuối cùng.

Mã nhúng AdBubbles, adbubbles.js, tải sau khi DOM của trang đã sẵn sàng. Đó là một tệp tĩnh duy nhất, được phân phối qua bộ nhớ đệm của Cloudflare và viết bằng JavaScript thuần không có phụ thuộc. Dữ liệu theo trang web mà nó đọc cũng là một tệp tĩnh, được tạo lại khi một chiến dịch thay đổi và được lưu đệm ở biên mạng. Do đó một lượt xem trang không tốn gì cho máy chủ quảng cáo, và yêu cầu động duy nhất là một beacon nhỏ. Mã nhúng chỉ quét phạm vi mà nhà xuất bản đã cấu hình, và bỏ qua tiêu đề, liên kết, mã, văn bản định dạng sẵn, điều khiển biểu mẫu, thanh điều hướng, header, footer và bất cứ thứ gì được đánh dấu data-noads. Ghi chú cài đặt mô tả thiết lập phạm vi.

Mở tài khoản nhà xuất bản không tốn chi phí nào, và thêm mã nhúng vào trang web cũng vậy. Nhà xuất bản thêm trang web có thể yêu cầu một lượt quét cho thấy những từ nào của trang hiện có thể bán. Phạm vi, số bong bóng tối đa mỗi trang và các danh mục nhà quảng cáo bị loại trừ đều được chọn từ cùng tài khoản đó.

Beacon được gửi khi người đọc rời đi là nửa còn lại của chi phí

Thời điểm người đọc rời đi là cơ hội còn lại để một script làm họ chậm lại. Mã phân tích báo cáo khi trang đóng từng dựa vào các kỹ thuật như “một lệnh gọi XMLHttpRequest đồng bộ gây chặn.”7 MDN ghi nhận rằng tất cả các phương pháp đó “chặn việc đóng tài liệu, làm chậm việc điều hướng đến trang tiếp theo.” Phương thức sendBeacon thay thế chúng. Nó gửi một yêu cầu HTTP POST nhỏ một cách bất đồng bộ. Trình duyệt truyền dữ liệu “khi tác nhân người dùng có cơ hội làm việc đó, mà không làm chậm việc đóng trang hay lần điều hướng tiếp theo.”

Mã nhúng báo cáo bằng sendBeacon, và nó gửi ba loại beacon. Một lượt xem được gửi cho mỗi lần tải trang. Một lượt mở được gửi khi bong bóng đã hiển thị được một giây, và một lượt nhấp được gửi khi người đọc mở liên kết bên trong bong bóng. Không có gì khác rời khỏi trang.

AdBubbles không đặt cookie, không lưu mã nhận dạng và không thu thập dữ liệu cá nhân của người đọc. Quốc gia của người đọc được đọc từ một header yêu cầu của Cloudflare thay vì từ một địa chỉ IP được lưu. Ghép các từ trên trang của nhà xuất bản với nhà quảng cáo đã mua chúng là toàn bộ những gì AdBubbles làm. AdBubbles không có tiếng nói nào về việc ai được xem bong bóng, không bao giờ theo dõi người đọc từ trang hay trang web này sang trang khác, và không hứa hẹn kết quả nào. Lập trường về quyền riêng tư được công bố đầy đủ.

Trình duyệt giờ đây tính toán chi phí của quảng cáo và hành động dựa trên tổng số

Can thiệp Quảng cáo Nặng (Heavy Ad Intervention) của Chrome cho thấy một nhà sản xuất trình duyệt coi thế nào là quá nhiều. Một quảng cáo chỉ được coi là nặng “nếu người dùng chưa tương tác với nó (ví dụ, chưa chạm hoặc nhấp vào nó).”8 Ngoài điều đó, chỉ cần một trong ba ngưỡng là đủ. Ngưỡng thứ nhất là hơn 4 megabyte băng thông mạng. Ngưỡng thứ hai là hơn 15 giây thời gian luồng chính trong bất kỳ khoảng 30 giây nào, và ngưỡng thứ ba là tổng cộng hơn 60 giây.

Khi can thiệp được kích hoạt, nội dung của khung quảng cáo được “thay bằng thông báo Ad removed (Quảng cáo đã bị gỡ bỏ),” và cơ chế này tác động lên các iframe được gắn thẻ quảng cáo.8 Thước đo là số byte và thời gian luồng chính; nội dung của quảng cáo không có vai trò gì. Một bong bóng được hiển thị bên trong một Shadow DOM trong chính tài liệu của nhà xuất bản chứ không phải trong một iframe, nên cơ chế này nhắm vào một loại quảng cáo khác. Mã nhúng thêm bao nhiêu vào một trang cụ thể, về số byte và thời gian luồng chính, là điều mà chính các phép đo của trang đó sẽ cho thấy.

Phép kiểm tra mà nhà xuất bản có thể thực hiện trên trang của mình không cần gì ngoài một trình duyệt. Mã nguồn trang liệt kê mọi phần tử script trong head, và mỗi phần tử hoặc mang async hay defer, hoặc không mang thuộc tính nào. Mục Opportunities (Cơ hội) của Lighthouse liệt kê những phần tử không mang thuộc tính nào là các URL đang chặn lần vẽ đầu tiên.4 Đoạn mã của một mạng lưới nằm trong danh sách đó là đang chặn trang theo định nghĩa của tiêu chuẩn, bất kể tài liệu của mạng lưới nói gì về dung lượng của nó. Việc một script quảng cáo có nằm trong danh sách đó hay không được quyết định bởi thuộc tính trên phần tử của nó, và thuộc tính đó đã được viết vào đoạn mã trước khi bất kỳ nhà xuất bản nào dán nó.