Вмешательство в 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 или медленный Wi-Fi.)
  2. document.write() находится в документе верхнего уровня. Вмешательство не применяется к сценариям document.writing внутри iframe, поскольку они не блокируют рендеринг главной страницы.
  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 к элементу сценария или добавить элементы сценария с помощью DOM API, например document.appendChild() или parentNode.insertBefore() .

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

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

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

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

Отлов предупреждений в 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 для сценария (асинхронно в случае фактического вмешательства).

Что в будущем?

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

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

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

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

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