Эквивалент $.ready() в чистом JavaScript - как вызвать функцию, когда страница/DOM готова
В jQuery мы все знаем замечательную функцию .ready():
$('document').ready(function(){});
Однако, допустим, я хочу запустить функцию, написанную на стандартном JavaScript без использования библиотек, и запустить её как только страница будет готова её обработать. Какой правильный подход к этому?
Я знаю, что могу сделать:
window.onload="myFunction()";
Или я могу использовать тег body:
<body onload="myFunction()">
Или я даже могу попробовать в конце страницы после всего, перед закрывающими тегами body или html, например:
<script type="text/javascript">
myFunction();
</script>
Какой кросс-браузерный (работающий как в старых, так и в новых браузерах) метод существует для вызова одной или нескольких функций, подобно jQuery’s $.ready()?
Ванильный JavaScript эквивалент jQuery $.ready()
Основным ванильным JavaScript эквивалентом jQuery $.ready() является событие DOMContentLoaded, которое срабатывает, когда первоначальный HTML-документ полностью загружен и обработан, без ожидания загрузки таблиц стилей, изображений и фреймов. Для кроссбраузерной совместимости, включая старые версии Internet Explorer, потребуется более комплексное решение, которое проверяет состояние готовности документа и использует соответствующие обработчики событий для разных браузеров.
Содержание
- Решение для современных браузеров
- Кроссбраузерная реализация
- Альтернативные подходы
- Совместимость с браузерами
- Рекомендуемое решение
Решение для современных браузеров
Наиболее прямой подход для современных браузеров — использование события DOMContentLoaded:
document.addEventListener("DOMContentLoaded", function() {
// Ваш код здесь
console.log("DOM готов!");
});
Это прямой эквивалент jQuery $(document).ready() и работает во всех современных браузерах, включая Chrome, Firefox, Safari и IE9+ [источник]. Событие срабатывает, когда DOM полностью загружен, но до завершения загрузки изображений и других внешних ресурсов, что делает его быстрее, чем window.onload.
Кроссбраузерная реализация
Для полной кроссбраузерной совместимости, включая старые версии Internet Explorer, требуется более надежное решение. Вот комплексная реализация, которая обрабатывает все браузеры от IE6 и выше:
function docReady(fn) {
// Проверяем, доступен ли DOM уже
if (document.readyState === "complete" || document.readyState === "interactive") {
// Вызываем на следующем доступном тике
setTimeout(fn, 1);
} else {
// Используем DOMContentLoaded для современных браузеров
document.addEventListener("DOMContentLoaded", fn);
}
}
// Использование
docReady(function() {
// Ваш код здесь
console.log("DOM готов!");
});
Для еще более широкой совместимости, включая IE8 и ниже, вот улучшенная версия:
function ready(fn) {
// Проверяем, загружен ли DOM уже
if (document.readyState !== 'loading') {
fn();
} else if (document.addEventListener) {
// Для современных браузеров
document.addEventListener('DOMContentLoaded', fn);
} else {
// Для IE8 и ниже
document.attachEvent('onreadystatechange', function() {
if (document.readyState === 'complete') {
fn();
}
});
}
}
// Использование
ready(function() {
// Ваш код здесь
console.log("DOM готов!");
});
Эта реализация обрабатывает различные способы, которыми браузеры сигнализируют о готовности DOM, работая во всех основных браузерах, включая IE6+ [источник]. Согласно решению для кроссбраузерности Рэймона Шоуэнаара, этот подход охватывает все версии браузеров.
Альтернативные подходы
Прямая проверка состояния документа
Можно проверить состояние готовности документа без использования событий:
function domReady(callback) {
if (document.readyState === "interactive" || document.readyState === "complete") {
callback();
} else {
document.addEventListener("DOMContentLoaded", callback);
}
}
domReady(function() {
// Ваш код здесь
});
Этот метод, как объясняется на Beeker.io, проверяет текущее состояние и либо выполняет немедленно, либо ожидает события.
Скрипт с атрибутом defer
Просто добавьте атрибут defer к тегу вашего скрипта:
<script src="your-script.js" defer></script>
Атрибут defer указывает браузеру загружать скрипт без блокировки разбора HTML и выполнять его после того, как документ будет обработан, но до DOMContentLoaded [источник]. Как упоминается в обсуждении на Reddit, это современная альтернатива функции ready jQuery.
Скрипт в конце body
Разместите тег вашего скрипта прямо перед закрывающим тегом </body>:
<!DOCTYPE html>
<html>
<head>
<title>Название страницы</title>
</head>
<body>
<!-- Ваш контент здесь -->
<script>
// Ваш код здесь
console.log("DOM готов!");
</script>
</body>
</html>
Это самый простой подход, который надежно работает во всех браузерах, хотя он не так гибок, как решения на основе событий [источник].
Совместимость с браузерами
Вот обзор совместимости для разных подходов:
| Метод | IE6-8 | IE9+ | Chrome | Firefox | Safari | Opera |
|---|---|---|---|---|---|---|
| DOMContentLoaded | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ |
| onreadystatechange | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| document.readyState | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Размещение скрипта | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Атрибут defer | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ |
Событие DOMContentLoaded поддерживается более чем 98% браузеров, но не IE8 и ниже [источник]. Для полной совместимости необходимо комбинировать несколько подходов, как показано в кроссбраузерной реализации.
Рекомендуемое решение
Для большинства современных проектов я рекомендую эту кроссбраузерную функцию ready:
function domReady(callback) {
// Если DOM уже загружен, выполнить callback
if (document.readyState === 'interactive' || document.readyState === 'complete') {
callback();
} else {
// Для современных браузеров
document.addEventListener('DOMContentLoaded', callback);
// Для IE8 и ниже
if (document.attachEvent) {
document.attachEvent('onreadystatechange', function() {
if (document.readyState === 'complete') {
callback();
}
});
}
}
}
// Использование
domReady(function() {
// Можно добавить несколько функций
initializeComponents();
setupEventListeners();
loadDynamicContent();
});
// Или создать пространство имен для нескольких функций
var DOMReady = {
callbacks: [],
add: function(callback) {
if (document.readyState === 'interactive' || document.readyState === 'complete') {
callback();
} else {
this.callbacks.push(callback);
}
},
ready: function() {
var callbacks = this.callbacks;
for (var i = 0; i < callbacks.length; i++) {
callbacks[i]();
}
}
};
// Добавьте ваши функции
DOMReady.add(function() {
console.log("Первая функция готова");
});
DOMReady.add(function() {
console.log("Вторая функция готова");
});
// Инициализировать при готовности DOM
domReady(DOMReady.ready);
Это решение обеспечивает:
- Полную кроссбраузерную совместимость (IE6+)
- Поддержку нескольких callback-функций
- Немедленное выполнение, если DOM уже готов
- Чистую, переиспользуемую структуру кода
Согласно статье на CSS-Tricks, этот подход эффективно работает во всех браузерах, сохраняя чистый, независимый от зависимостей код.
Источники
- Stack Overflow - Ванильный JavaScript эквивалент jQuery $.ready()
- GitHub - vanilla-ready
- Reddit - Что использовать вместо jQuery $(document).ready()?
- Stack Overflow - Какой не-jQuery эквивалент ‘$(document).ready()’?
- Raymon Schouwenaar - Кроссбраузерный Document Ready с ванильным JavaScript
- Beeker.io - jQuery $(document).ready() эквивалент в ванильном JavaScript
- CSS-Tricks - Кроссбраузерный независимый от зависимостей DOM Ready
- Wikitechy - $(document).ready эквивалент без jQuery
- WPShout - jQuery document.ready в ванильном JavaScript
- SitePoint - Замена функции jQuery Document Ready на JavaScript
Заключение
Ванильный JavaScript эквивалент jQuery $.ready() можно реализовать несколькими способами в зависимости от требований к совместимости с браузерами:
- Для современных браузеров: Используйте
document.addEventListener("DOMContentLoaded", callback)— это самый чистый и прямой подход - Для полной кроссбраузерной совместимости: Реализуйте функцию, которая проверяет
document.readyStateи использует какaddEventListener, так иattachEventдля старых версий IE - Для простоты: Размещайте скрипты в конце body или используйте атрибут
defer - Для нескольких функций: Создайте функцию ready, которая поддерживает массив callback-функций
Рекомендуемый подход сочетает современную обработку событий с поддержкой наследия, обеспечивая работу вашего кода во всех браузерах от IE6 до последних версий. Это решение сохраняет такое же поведение, как функция ready jQuery, при этом будучи легковесным и независимым от зависимостей.
Помните, что хотя window.onload работает, он ожидает загрузки всех ресурсов (изображений, таблиц стилей и т.д.), в то время как DOM-ready срабатывает, как только HTML-структура становится доступной, что делает его быстрее и более похожим на поведение jQuery.