Вмешательство в document.write()

Видели ли вы недавно подобное предупреждение в консоли разработчика в Chrome и задавались вопросом, что это такое?

(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.

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

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

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

Прежде чем браузер сможет отобразить страницу, он должен построить дерево DOM, проанализировав разметку HTML. Всякий раз, когда парсер встречает скрипт, он должен остановиться и выполнить его, прежде чем продолжить анализ HTML. Если скрипт динамически внедряет другой скрипт, парсер вынужден ждать загрузки ресурса еще дольше, что может повлечь за собой один или несколько сетевых циклов и задержать время первого отображения страницы

Для пользователей с медленным подключением, таким как 2G, внешние скрипты, динамически внедряемые через document.write() могут задерживать отображение содержимого главной страницы на десятки секунд или приводить к тому, что страницы либо не загружаются, либо загружаются так долго, что пользователь просто сдается. Основываясь на инструментировании в Chrome, мы узнали, что страницы со сторонними скриптами, внедренными через document.write() обычно загружаются в два раза медленнее, чем другие страницы в 2G.

Мы собрали данные 28-дневного полевого испытания на 1% стабильных пользователей Chrome, ограниченных пользователями с 2G-подключениями. Мы увидели, что 7,6% всех загрузок страниц на 2G включали по крайней мере один межсайтовый скрипт, блокирующий парсер, который был вставлен через document.write() в документ верхнего уровня. В результате блокировки загрузки этих скриптов мы увидели следующие улучшения этих загрузок:

  • На 10% больше загрузок страниц, достигающих первой отрисовки контента (визуальное подтверждение для пользователя того, что страница эффективно загружается), на 25% больше загрузок страниц, достигающих полностью проанализированного состояния, и на 10% меньше повторных загрузок, что свидетельствует об уменьшении разочарования пользователей.
  • Уменьшение среднего времени до первой содержательной отрисовки на 21% (более чем на одну секунду)
  • Среднее время, необходимое для анализа страницы, сократилось на 38% , что представляет собой улучшение почти на шесть секунд и значительно сокращает время, необходимое для отображения важной для пользователя информации.

Учитывая эти данные, Chrome, начиная с версии 55, вмешивается от имени всех пользователей, когда мы обнаруживаем этот известный плохой шаблон, изменяя способ обработки document.write() в Chrome (см. Статус Chrome ). В частности, Chrome не будет выполнять элементы <script> , внедренные через document.write() , если выполнены все следующие условия:

  1. Пользователь использует медленное соединение, особенно когда он использует 2G. (В будущем это изменение может быть распространено на других пользователей с медленными соединениями, такими как медленное 3G или медленный WiFi.)
  2. document.write() находится в документе верхнего уровня. Вмешательство не применяется к скриптам document.written внутри iframes, поскольку они не блокируют рендеринг главной страницы.
  3. Скрипт в document.write() блокирует парсер. Скрипты с атрибутами ' async ' или ' defer ' все равно будут выполняться.
  4. Скрипт не размещен на том же сайте. Другими словами, Chrome не будет вмешиваться в скрипты с соответствующим eTLD+1 (например, скрипт, размещенный на js.example.org, вставленный на www.example.org).
  5. Скрипт еще не находится в HTTP-кэше браузера. Скрипты в кэше не вызовут сетевой задержки и будут по-прежнему выполняться.
  6. Запрос страницы не является перезагрузкой. Chrome не будет вмешиваться, если пользователь инициировал перезагрузку, и выполнит страницу как обычно.

Сниппеты третьих сторон иногда используют document.write() для загрузки скриптов. К счастью, большинство третьих сторон предоставляют альтернативы асинхронной загрузки , которые позволяют сторонним скриптам загружаться, не блокируя отображение остального контента на странице.

Как это исправить?

Этот простой ответ — не внедряйте скрипты с помощью document.write() . Мы поддерживаем набор известных сервисов для поддержки асинхронного загрузчика , которые мы рекомендуем вам проверять.

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

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

Если ваш поставщик предоставляет вам фрагмент, включающий document.write() , вы можете добавить атрибут async к элементу script или добавить элементы script с помощью API DOM, например document.appendChild() или parentNode.insertBefore() .

Как определить, что ваш сайт затронут

Существует множество критериев, определяющих, применяется ли ограничение. Как узнать, касается ли оно вас?

Определение, когда пользователь находится в сети 2G

Чтобы понять потенциальное влияние этого изменения, вам сначала нужно понять, сколько ваших пользователей будут на 2G. Вы можете определить текущий тип сети и скорость пользователя, используя API сетевой информации , доступный в Chrome, а затем отправить уведомление в ваши аналитические системы или системы Real User Metrics (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.
}

Предупреждения Catch в Chrome DevTools

Начиная с Chrome 53, DevTools выдает предупреждения для проблемных операторов document.write() . В частности, если запрос document.write() соответствует критериям 2–5 (Chrome игнорирует критерии соединения при отправке этого предупреждения), предупреждение будет выглядеть примерно так:

Предупреждение о записи документа.

Видеть предупреждения в Chrome DevTools — это здорово, но как обнаружить это в масштабе? Вы можете проверить заголовки HTTP, которые отправляются на ваш сервер, когда происходит вмешательство.

Проверьте заголовки HTTP на ресурсе скрипта.

Если скрипт, вставленный через document.write , заблокирован, Chrome отправит следующий заголовок запрошенному ресурсу:

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

Если обнаружен скрипт, вставленный через document.write , и его можно заблокировать при различных обстоятельствах, Chrome может отправить:

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

Заголовок вмешательства будет отправлен как часть запроса GET для скрипта (асинхронно в случае фактического вмешательства).

Что нас ждет в будущем?

Первоначальный план заключается в том, чтобы выполнить это вмешательство, когда мы обнаружим, что критерии выполняются. Мы начали с показа только предупреждения в Developer Console в Chrome 53. (Бета-версия была в июле 2016 года. Мы ожидаем, что Stable будет доступна для всех пользователей в сентябре 2016 года.)

Мы вмешаемся, чтобы заблокировать внедренные скрипты для пользователей 2G, ориентировочно начиная с Chrome 54, который, как ожидается, станет стабильным релизом для всех пользователей в середине октября 2016 года. Ознакомьтесь с записью о состоянии Chrome для получения дополнительных обновлений.

Со временем мы постараемся вмешаться, когда у пользователя медленное соединение (например, медленное 3G или WiFi). Следуйте этой записи статуса Chrome .

Хотите узнать больше?

Чтобы узнать больше, ознакомьтесь с этими дополнительными ресурсами: