Avatar ·

Как заменить $(document).ready() на чистом JavaScript без jQuery?

Всем привет! Я только начал изучать JavaScript и раньше пользовался jQuery. Там я привык писать такой код: ```javascript $(document).ready(function() { // мой код, который выполняется после загрузки DOM console.log('Страница готова!'); }); ``` Или сокращённый вариант: ```javascript $(function() { // код }); ``` Сейчас я хочу отказаться от jQuery, чтобы уменьшить размер страницы и писать на чистом JavaScript. Но я не знаю, как правильно сделать аналог `$(document).ready()` в нативном JS. Проблема в том, что если я просто напишу скрипт в `` или в начале ``, то он может выполниться до того, как DOM-дерево будет полностью построено. Например, я пытаюсь обратиться к элементу, которого ещё нет: ```javascript document.querySelector('.my-class').textContent = 'Привет!'; // Ошибка: элемент null ``` Как правильно дождаться полной загрузки DOM на чистом JavaScript? Есть ли несколько способов это сделать? И чем они отличаются? Очень хочу понять, как это работает без jQuery, потому что хочу писать более производительный код. Спасибо! <<>>

Основной способ: событие DOMContentLoaded

Самый правильный и рекомендуемый аналог $(document).ready() в чистом JavaScript — это использование события DOMContentLoaded. Оно срабатывает сразу после того, как браузер полностью загрузил и распарсил HTML-документ, но до загрузки изображений, стилей и других внешних ресурсов.

Вот как это выглядит:

document.addEventListener('DOMContentLoaded', function() {
    // Ваш код выполнится после полной загрузки DOM
    console.log('DOM готов!');
    document.querySelector('.my-class').textContent = 'Привет!';
});

Если вы используете стрелочную функцию (современный синтаксис):

document.addEventListener('DOMContentLoaded', () => {
    // код
});

Второй способ: размещение скрипта перед закрывающим тегом </body>

Это самый простой и часто используемый метод. Если вы поместите тег <script> прямо перед </body>, то к моменту его выполнения весь DOM уже будет построен. Никаких дополнительных обработчиков не нужно:

<!DOCTYPE html>
<html>
<head>
    <title>Моя страница</title>
</head>
<body>
    <div class="my-class">Текст</div>
    
    <!-- Скрипт в конце body -->
    <script>
        // DOM уже загружен, можно работать
        document.querySelector('.my-class').textContent = 'Привет!';
    </script>
</body>
</html>

Третий способ: атрибут defer в теге <script>

Современный и элегантный способ. Атрибут defer говорит браузеру: «Загружай скрипт параллельно с HTML, но выполни только после полного парсинга документа». Это работает даже если скрипт находится в <head>:

<!DOCTYPE html>
<html>
<head>
    <title>Моя страница</title>
    <script defer src="script.js"></script>
</head>
<body>
    <div class="my-class">Текст</div>
</body>
</html>

В файле script.js вы можете писать код без обёрток:

// Этот код выполнится после загрузки DOM
document.querySelector('.my-class').textContent = 'Привет!';

Важные отличия от jQuery

  • DOMContentLoaded vs load: Событие load (window.onload) ждёт загрузки ВСЕХ ресурсов (картинки, iframe и т.д.) — это аналог $(window).on('load', fn), а не ready().
  • Несколько обработчиков: Вы можете добавить сколько угодно подписчиков на DOMContentLoaded — они все выполнятся по очереди.
  • Проверка готовности: Если DOM уже загружен, а вы подписываетесь на событие, оно не сработает. Для защиты используйте проверку document.readyState:
function onDOMReady(callback) {
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', callback);
    } else {
        callback(); // DOM уже готов, вызываем сразу
    }
}

// Использование:
onDOMReady(() => {
    console.log('DOM готов!');
});

Итог: лучший способ в 2024 году — использовать defer для внешних скриптов или DOMContentLoaded для inline-скриптов. Это даёт ту же функциональность, что и jQuery, но без лишнего веса библиотеки.

<<>>

Альтернатива: самодельная функция-замена ready()

Если вы хотите сохранить привычный синтаксис в стиле jQuery, можно написать свою маленькую функцию-обёртку:

function ready(fn) {
    if (document.readyState !== 'loading') {
        fn();
    } else {
        document.addEventListener('DOMContentLoaded', fn);
    }
}

// Используем почти как в jQuery:
ready(function() {
    console.log('DOM готов!');
    document.querySelector('.my-class').textContent = 'Работает!';
});

Этот код проверяет, не загружен ли уже DOM. Если да — вызывает функцию сразу, если нет — подписывается на событие.

Для очень старых браузеров (IE8 и ниже)

Если вам нужно поддерживать совсем древние браузеры, можно использовать событие onreadystatechange:

document.onreadystatechange = function() {
    if (document.readyState === 'interactive' || document.readyState === 'complete') {
        // Ваш код
    }
};

Но в современной разработке это не нужно — все актуальные браузеры поддерживают DOMContentLoaded и defer.

Совет: Начните с defer — это самый простой способ, который не требует написания лишнего кода и работает «из коробки».