Из JavaScript на медианной мобильной странице в Web Almanac 2024 года 168 килобайт были собственными, а 375 килобайт — сторонними.1 Больше половины скриптов на обычной странице по объёму написал кто-то другой, а не владелец сайта. Глава Almanac о третьих сторонах обнаружила их на 92 процентах страниц, причём скрипт был самым распространённым типом стороннего запроса.2 Скрипт рекламной сети — тот, который издатель добавляет, чтобы показывать её рекламу, — один из таких запросов. То, чего этот скрипт стоит странице при загрузке, зависит не столько от того, что он делает, сколько от того, как написан загружающий его элемент.

Браузер останавливается на элементе script без атрибутов

Согласно HTML Living Standard, у браузера есть три способа обработать внешний скрипт, и различаются они лишь атрибутом элемента.3 Первый, без атрибутов, — поведение по умолчанию: скрипт «загружается и выполняется немедленно, блокируя разбор, пока и то и другое не завершится». Второй, defer, загружает файл параллельно с разбором и выполняет его, «когда страница закончит разбор». При третьем, async, файл тоже загружается параллельно, но выполняется, «как только становится доступен (возможно, до завершения разбора)». Только первый режим удерживает парсер, пока файл идёт по сети, и ничего после элемента не отрисовывается, пока файл не придёт.

Аудит Google Lighthouse превращает это различие в проверку, которую издатель может запустить на собственной странице. Он отмечает элемент script в head документа, у которого нет ни defer, ни async.4 Отчёт «перечисляет все URL, блокирующие первую отрисовку вашей страницы». Размер в это определение не входит, как и назначение. Скрипт аналитики, рекламный скрипт и загрузчик шрифтов рассматриваются одинаково, если они стоят в head без атрибута.

Сторонний скрипт — тот случай, для которого писались рекомендации по загрузке

Рекомендации на web.dev прямо говорят о скриптах извне сайта. Синхронные скрипты, сказано там, «задерживают построение DOM и отрисовку»; DOM — это рабочая модель документа в браузере.5 Из этого следует правило: «всегда загружайте сторонние скрипты асинхронно, если только скрипт не должен выполниться до того, как страницу можно будет отрисовать». Async подходит для скрипта, который должен выполниться на раннем этапе загрузки; defer — для «менее важных ресурсов», и в качестве примера приводится видеоплеер ниже первого экрана. Рекламный скрипт, который работает после того, как текст появился на экране, по этому критерию относится к менее важным.

Эта практика распространилась, хотя и не на все страницы. Web Almanac 2024 года обнаружил async на 87 процентах страниц, по сравнению с 76 процентами в 2022 году, и defer на 47 процентах, по сравнению с 42 процентами.1 Эти цифры описывают страницы в целом. Страница, собственные скрипты которой отложены, всё равно может содержать один блокирующий элемент, предоставленный третьей стороной. Фрагмент кода для установки, если издатель его не изменит, загружается так, как его написала сеть.

Скрипту, который ждёт DOM, нечего блокировать при первой отрисовке

Момент, когда парсер заканчивает строить DOM, браузер отмечает событием. Согласно MDN, DOMContentLoaded «срабатывает, когда HTML-документ полностью разобран, а все отложенные скрипты» загружены и выполнены.6 Событие не ждёт изображений, вложенных фреймов или асинхронных скриптов. Поэтому скрипт, который начинает работу в этот момент, стартует после того, как текст уже существует, не дожидаясь последнего изображения.

Скрипт встраивания AdBubbles, adbubbles.js, загружается после того, как DOM страницы готов. Это один статический файл, отдаваемый через кэш Cloudflare и написанный на чистом JavaScript без зависимостей. Данные по сайту, которые он читает, — тоже статический файл, который пересоздаётся при изменении кампании и кэшируется на периферии сети. Поэтому просмотр страницы ничего не стоит рекламному серверу, а единственный динамический запрос — небольшой маячок. Скрипт сканирует только область, которую настроил издатель, и пропускает заголовки, ссылки, код, предварительно отформатированный текст, элементы форм, навигацию, шапку, подвал и всё, что помечено data-noads. Заметки по установке описывают настройку области.

Открытие аккаунта издателя ничего не стоит, как и добавление скрипта встраивания на сайт. Издатель, который добавляет сайт, может запросить обход, показывающий, какие слова сайта сейчас можно продать. Область, максимальное число пузырей на странице и исключаемые категории рекламодателей выбираются в том же аккаунте.

Маячок, отправляемый при уходе читателя, — вторая половина цены

Момент, когда читатель уходит, — ещё одна возможность для скрипта его задержать. Код аналитики, отправлявший данные при выгрузке страницы, когда-то полагался на такие приёмы, как «блокирующий синхронный вызов XMLHttpRequest».7 MDN отмечает, что все эти методы «блокируют выгрузку документа, что замедляет переход на следующую страницу». Метод sendBeacon заменяет их. Он асинхронно отправляет небольшой HTTP-запрос POST. Браузер передаёт данные, «когда у пользовательского агента есть возможность это сделать, не задерживая выгрузку или следующий переход».

Скрипт встраивания отправляет данные через sendBeacon, и маячки бывают трёх видов. Один просмотр отправляется на загрузку страницы. Одно открытие отправляется, когда пузырь был виден одну секунду, и один клик — когда читатель переходит по ссылке внутри пузыря. Больше ничего со страницы не уходит.

AdBubbles не устанавливает cookie, не хранит идентификаторов и не собирает персональные данные читателей. Страна читателя определяется по заголовку запроса Cloudflare, а не по сохранённому IP-адресу. Сопоставление слов на страницах издателя с рекламодателем, который их купил, — это всё, что делает AdBubbles. AdBubbles никак не влияет на то, какие люди видят пузырь, никогда не следит за читателем при переходе с одной страницы или сайта на другие и не обещает результата. Позиция в отношении конфиденциальности опубликована полностью.

Браузеры теперь считают, сколько стоит реклама, и действуют по итогу

Вмешательство Chrome в тяжёлую рекламу (Heavy Ad Intervention) показывает, что один производитель браузеров считает чрезмерным. Реклама считается тяжёлой, только «если пользователь не взаимодействовал с ней (например, не касался её и не нажимал на неё)».8 Сверх этого достаточно любого из трёх порогов. Первый — более 4 мегабайт сетевого трафика. Второй — более 15 секунд работы основного потока в любом 30-секундном окне, третий — более 60 секунд в сумме.

Когда срабатывает вмешательство, содержимое рекламного фрейма «заменяется сообщением о том, что реклама удалена» (Ad removed), и механизм действует на iframe, помеченные как рекламные.8 Мерой служат байты и время основного потока; содержание рекламы роли не играет. Пузырь отрисовывается внутри Shadow DOM в собственном документе издателя, а не в iframe, поэтому этот механизм нацелен на рекламу другого рода. Что скрипт встраивания добавляет к конкретной странице в байтах и во времени основного потока, покажут собственные измерения этой страницы.

Проверка, которую издатель может провести на собственной странице, не требует ничего, кроме браузера. Исходный код страницы перечисляет все элементы script в head, и у каждого есть либо async или defer, либо ни того, ни другого. Раздел Opportunities («Возможности») в Lighthouse перечисляет те, у которых нет ни того, ни другого, как URL, блокирующие первую отрисовку.4 Фрагмент кода сети, попавший в этот список, блокирует страницу по определению стандарта, что бы ни говорила документация сети о его весе. Попадёт ли рекламный скрипт в этот список, решает атрибут его элемента, а атрибут записан во фрагмент кода ещё до того, как какой-либо издатель его вставит.