Жизненный цикл страницы: DOMContentLoaded, load, beforeunload, unload

Жизненный цикл HTML-страницы состоит из трех важных событий:

  • DOMContentLoaded — браузер в полном объеме загрузил HTML-код страницы и построил дерево DOM. Но внешние ресурсы, такие как картинки <img> и таблицы стилей, могут все ещё загружаться;
  • onload JavaScript — браузер загрузил все ресурсы(картинки, стили и т. д.);
  • beforeunload/unload — когда посетитель покидает страницу.

Каждое событие может использоваться для разных целей:

  • Событие DOMContentLoadedDOM готов, так что обработчик может искать узлы DOM, инициализировать интерфейс.
  • Событие load — загружаются дополнительные ресурсы, и можно приобретать размеры картинок(если это не указано в HTML / CSS) и т. д.
  • Событие beforeunload/unload — посетитель покидает страницу. Можно проверить, сохранил ли посетитель изменения, и спросить его, действительно ли он хочет уйти.

Рассмотрим данные события подробнее.

DOMContentLoaded

Событие DOMContentLoaded происходит в объекте документа. Надо использовать addEventListener, чтобы отследить его:

document.addEventListener("DOMContentLoaded", ready);

К примеру:

<script> function ready() { alert('DOM is ready'); // картинки ещё не загрузились(если только не были сохранены в кэше), так что их размер 0x0 alert(`Image size: ${img.offsetWidth}x${img.offsetHeight}`); } document.addEventListener("DOMContentLoaded", ready);</script><img id="img" src="https://en.js.cx/clipart/train.gif?speed=1&cache=0">

В этом примере обработчик DOMContentLoaded запускается при загрузке документа(не при JavaScript onload), и не ждет полной загрузки страницы. Таким образом, предупреждение сообщает, что размер картинок равен нулю.

На первый взгляд событие DOMContentLoaded простое. Но есть пару особенностей.

DOMContentLoaded и скрипты

Когда браузер загружает HTML и встречает в коде <script> … </ script>, он не может продолжить создание DOM. Он должен выполнить скрипт напрямую теперь. Так что DOMContentLoaded может произойти только после выполнения всех скриптов.

Внешние скрипты(подключаемые при помощи src) также приостанавливают создание DOM, пока скрипт загружается и выполняется. Так что DOMContentLoaded ожидает выполнения внешних скриптов.

Единственным исключением являются внешние скрипты с атрибутами async и defer. Они указывают браузеру продолжать обработку, не дожидаясь выполнения скриптов. Таким образом, посетитель может увидеть страницу до завершения загрузки скриптов, что отлично для производительности.

Пару слов об async и defer

Атрибуты async и defer в window onload JavaScript используются только для внешних скриптов. Они игнорируются, если нет подключения через src.

Оба атрибута указывают браузеру, что он может продолжать обрабатывать страницу и загружать скрипты «в фоновом режиме». А далее запускать скрипт после его полной загрузки. Таким образом, скрипт не блокирует создание DOM и вывод страниц.

Между данными атрибутами есть два отличия.

async Defer
Порядок Скрипты с атрибутом async выполняются в том порядке, в котором они загружаются. Порядок, в котором они указаны в документе, не имеет в себя значения — скрипт, загруженный первым, выполняется первым. Скрипты с атрибутом defer выполняются в соответствии с порядком, в котором они расположены в документе.
DOMContentLoaded Скрипты с атрибутом async могут загружаться и выполняться, пока документ ещё не загружен в полном объеме. Это происходит, когда скрипты являются небольшими или кэшируются, а документ достаточно объемен. Скрипты с атрибутом defer выполняются после того, как документ будет в полном объеме загружен и обработан(если надо они ожидают завершения процесса), сразу же после события DOMContentLoaded.

Атрибут async используется для в полном объеме независимых скриптов.

DOMContentLoaded и стили

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

<link type="text/css" rel="stylesheet" href="style.css"><script> // скрипт не будет выполняться до тех пор, пока не загружены таблицы стиле alert(getComputedStyle(document.body).marginTop);</script>

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

Так как DOMContentLoaded ожидает загрузки скриптов( document onload JavaScript), он должен дождаться и загрузки стилей.

Автоматическое заполнение браузерами

Firefox, Chrome и Opera автоматом заполняют поля ввода форм для DOMContentLoaded. К примеру, если страница имеет в себя форму с полями ввода для ввода имени посетителя и пароля, а браузер запомнил их значения, DOMContentLoaded может попытаться автоматически их заполнить(если это одобрено посетителем).

Так что, кроме задержки до полной загрузки и выполнения скриптов, DOMContentLoaded может задерживаться и из-за автоматического заполнения полей ввода форм. Вы могли сталкиваться с данным на некоторых веб-сайтах: поля ввода ввода логина / пароля не обновляются автоматически, и возникает задержка до полной загрузки страницы. Фактически это задержка события DOMContentLoaded.

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

window.onload

Событие window onload JavaScript запускается после полной загрузки страницы, включая стили, картинки и иные ресурсы.

В приведенном ниже примере правильно выводятся размеры картинок, поскольку window.onload ожидает загрузки всех картинок:

<script> window.onload = function() { alert('Page loaded'); // на данный момент картинки загружены alert(`Image size: ${img.offsetWidth}x${img.offsetHeight}`); };</script><img id="img" src="https://en.js.cx/clipart/train.gif?speed=1&cache=0">

window.onunload

Когда пользователь покидает страницу, для объекта window запускается событие unload. При этом можно выполнить определенные действия, не связанные с задержкой. К примеру, закрыть всплывающие окна. Но нельзя отменить переход на другую страницу. Для этого надо использовать иное событие — onbeforeunload.

window.onbeforeunload

Если пользователь покидает страницу или пытается закрыть окно, обработчик beforeunload может запросить дополнительное подтверждение. Этот обработчик возвращает строку с вопросом. Браузер отобразит ее.

К примеру:

window.onbeforeunload = function() { return "Некоторые изменения не были сохранены. Вы все равно желаете покинуть страницу?";};

Некоторые браузеры, такие как Chrome и Firefox, игнорируют заданное значение и выводят собственное сообщение. Делается это из соображений безопасности, чтобы защитить посетителя от мошеннических и хакерских сообщений при наступлении события JavaScript onload.

readyState

Что произойдет, если установить обработчик DOMContentLoaded после загрузки документа? Естественно, он никогда не запустится.

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

Свойство document.readyState предлагает такую информацию. Возможны три значения:

  • «loading» — документ загружается;
  • «interactive» — документ в полном объеме считан;
  • «complete» — документ в полном объеме считан и все ресурсы(к примеру, картинки) загружены.

Так можно легко проверить значение document.readyState и изменить обработчик или выполнить программный код немедленно, как только он будет готов.

Например, следующим образом:

function work() { /*...*/ }if (document.readyState == 'loading') { document.addEventListener('DOMContentLoaded', work);} else { work();}

Событие readystatechange запускается при изменении состояния. Можно без труда отображать все данные состояния следующим образом:

// текущее состояниеconsole.log(document.readyState);// выводим изменение состоянияdocument.addEventListener('readystatechange', () => console.log(document.readyState));

Событие readystatechange будет альтернативным способом отслеживания состояния загрузки документа, оно было введено давно. В настоящее время оно редко используется, но рассмотрим его для полноты картины.

Как размещается readystatechange по отношению к иным событиям? Чтобы продемонстрировать порядок их срабатывания, ниже приводится пример с <iframe>, <img> и обработчиками, которые регистрируют события ( JavaScript onload и иные):

<script> function log(text) { /* выводим время и сообщение */ } log('initial readyState:' + document.readyState); document.addEventListener('readystatechange', () => log('readyState:' + document.readyState)); document.addEventListener('DOMContentLoaded', () => log('DOMContentLoaded')); window.onload = () => log('window onload');</script><iframe src="iframe.html" onload="log('iframe onload')"></iframe><img src="http://en.js.cx/clipart/train.gif" id="img"><script> img.onload = () => log('img onload');</script>

Демо-версию можно без проблем найти на sandbox .

Стандартная последовательность событий:

  1. [1] инициализация readyState:loading;
  2. [2] readyState:interactive;
  3. [2] DOMContentLoaded;
  4. [3] iframe onload;
  5. [4] readyState:complete;
  6. [4] img onload;
  7. [4] window onload JavaScript.

Цифры в квадратных скобках обозначают приблизительное время, когда это происходит. Реальное время больше, но события с одинаковой цифрой срабатывают примерно в одно и то же время (± пару миллисекунд).

Document.readyState принимает состояние interactive непосредственно перед DOMContentLoaded . Данные два события фактически означают одно и то же.

Document.readyState завершается, когда загружаются все ресурсы ( iframe и img ). Мы видим, что это происходит примерно в то же время, что и img.onload ( img — последний ресурс) и window.onload . Переключение на состояние complete означает то же, что и window.onload . Разница в том, что window.onload запускается после всех иных обработчиков load .

Заключение

События жизненного цикла страницы:

  • DOMContentLoaded инициирует события в документе, когда DOM готов. На этом этапе можно применить к элементам JavaScript :

— Выполняются все скрипты, кроме внешних, подключаемых с использованием атрибутов async или defer ; — Картинки и иные ресурсы могут увеличивать время загрузки.

  • Когда страница и ресурсы загружены, для объекта window запускается событие load . Мы редко его используем, так как обычно не необходимо так долго ждать;
  • Событие JavaScript onload запускается для объекта window , когда посетитель хочет покинуть страницу. Если при этом возвращается строка, браузер выводит сообщение с вопросом о том, действительно ли посетитель хочет покинуть страницу;
  • Событие unload запускается для объекта window , когда посетитель окончательно покидает страницу. В обработчике можно выполнять простые действия, которые не связаны с задержками или запросом посетителя. Из-за этого ограничения данное событие используется редко;
  • Document.readyState — это текущее состояние документа, изменения могут отслеживаться в событии readystatechange :

loading — документ загружается; — interactive — документ анализируется. Это происходит примерно в то же время, что и событие DOMContentLoaded , но непосредственно перед ним; — complete — документ и все ресурсы загружены. Происходит примерно в то же время, что и событие window onload JavaScript , но непосредственно перед ним.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *