Avatar ·

Как в чистом JavaScript (Vanilla JS) заменить $(document).ready() и выполнить код после загрузки DOM?

Привет всем! Я только начал изучать JavaScript, и до этого немного работал с jQuery. Там всё было просто: чтобы выполнить код после того, как страница загрузится и DOM-дерево будет готово, я писал: ```javascript $(document).ready(function() { // мой код }); ``` Или сокращённо: ```javascript $(function() { // мой код }); ``` Сейчас я решил отказаться от jQuery и писать на чистом JavaScript (Vanilla JS), чтобы уменьшить размер страницы и лучше понимать, как всё работает под капотом. Но столкнулся с проблемой: как правильно сделать аналог `$.ready()`? Я пробовал использовать `window.onload`, но это срабатывает только после полной загрузки всех изображений и стилей, а мне нужно выполнить код сразу, как только DOM построен. Например, я хочу повесить обработчики событий на кнопки или изменить текст в элементах, которые уже есть в HTML. Пробовал ставить скрипт в конце `` — это работает, но я слышал, что есть более правильный способ. Подскажите, как на чистом JavaScript дождаться готовности DOM и выполнить функцию? Желательно с примерами кода. Заранее спасибо! <<>>

Правильный способ: слушатель события DOMContentLoaded

В чистом JavaScript для выполнения кода после построения DOM (но до полной загрузки изображений и других ресурсов) используется событие DOMContentLoaded на объекте document. Это самый точный аналог jQuery $(document).ready().

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

document.addEventListener('DOMContentLoaded', function() {
    // Ваш код, который выполнится после построения DOM
    console.log('DOM готов!');
    const button = document.getElementById('myButton');
    button.addEventListener('click', function() {
        alert('Кнопка нажата!');
    });
});

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

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

Почему это лучше, чем window.onload?

  • DOMContentLoaded срабатывает, как только браузер построил DOM-дерево из HTML. Изображения, стили, фреймы могут ещё загружаться — это не важно.
  • window.onload ждёт загрузки ВСЕХ ресурсов (картинки, iframe, стили). Если на странице много тяжёлых изображений, пользователь будет ждать, прежде чем код выполнится.
  • К тому же window.onload можно назначить только один раз (если написать window.onload = fn, то предыдущий обработчик перезапишется), а через addEventListener можно вешать сколько угодно обработчиков.

Что, если DOM уже готов?

Иногда скрипт может выполниться уже после того, как событие DOMContentLoaded произошло (например, если скрипт загружается асинхронно). В этом случае обработчик не сработает. Чтобы быть уверенным, можно проверить состояние документа:

function domReady(callback) {
    if (document.readyState === 'loading') {
        // DOM ещё строится — ждём событие
        document.addEventListener('DOMContentLoaded', callback);
    } else {
        // DOM уже готов — вызываем сразу
        callback();
    }
}

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

Проверка на существование jQuery (на всякий случай)

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

function ready(fn) {
    if (typeof jQuery !== 'undefined') {
        // Если jQuery подключён — используем его
        jQuery(fn);
    } else {
        // Иначе — чистый JS
        if (document.readyState !== 'loading') {
            fn();
        } else {
            document.addEventListener('DOMContentLoaded', fn);
        }
    }
}

// Теперь можно писать:
ready(function() {
    console.log('Сработает в любом случае');
});

Важное замечание про атрибут defer

Если вы подключаете скрипт через тег <script> с атрибутом defer, то он выполнится автоматически после построения DOM, и оборачивать код в DOMContentLoaded не нужно:

<script src="script.js" defer></script>

Но если вы используете async или обычный скрипт в <head>, то без DOMContentLoaded не обойтись.

Таким образом, лучшая практика для Vanilla JS — использовать document.addEventListener('DOMContentLoaded', handler) или универсальную обёртку с проверкой состояния. Это надёжно, просто и полностью заменяет jQuery $.ready().

<<>>

Альтернативный подход: размещение скрипта в конце body

Самый простой способ, который не требует никаких событий — просто поместить ваш тег <script> перед закрывающим тегом </body>. К тому моменту, как браузер дойдёт до скрипта, весь DOM уже будет построен (ведь HTML парсится сверху вниз).

<!DOCTYPE html>
<html>
<head>
    <title>Пример</title>
</head>
<body>
    <button id="myButton">Нажми меня</button>
    
    <!-- Скрипт в конце body -->
    <script>
        const button = document.getElementById('myButton');
        button.addEventListener('click', () => {
            alert('Кнопка нажата!');
        });
        console.log('DOM готов, скрипт выполняется');
    </script>
</body>
</html>

Этот метод работает без единого обработчика событий. Однако у него есть минусы:

  • Скрипт блокирует парсинг страницы, пока загружается и выполняется (если не использовать async/defer).
  • Если скрипт внешний (src="..."), его загрузка задержит отрисовку.
  • Не подходит, если вы хотите выполнить код до того, как страница полностью отрендерится (например, показать спиннер загрузки).

Поэтому для серьёзных проектов рекомендую использовать DOMContentLoaded из первого ответа. Но для быстрых прототипов или учебных примеров — размещение скрипта в конце <body> вполне допустимо.