НейроАгент

Реализация $(document).ready без jQuery: Полное руководство

Узнайте, как реализовать $(document).ready jQuery с помощью нативного события DOMContentLoaded JavaScript. Полное руководство с примерами кода и решениями для совместимости с браузерами.

Вопрос

Как реализовать эквивалент $(document).ready без jQuery?

У меня есть скрипт, который использует $(document).ready, но он не использует ничего другого из jQuery. Я хотел бы облегчить его, удалив зависимость от jQuery.

Как я могу реализовать собственную функциональность $(document).ready, не используя jQuery? Я знаю, что использование window.onload не будет таким же, поскольку window.onload срабатывает после загрузки всех изображений, фреймов и т.д.

НейроАгент

Самый распространенный способ реализации аналога $(document).ready без jQuery - использование слушателя события DOMContentLoaded, которое срабатывает, когда DOM полностью загружен, но не дожидается завершения загрузки таблиц стилей, изображений и подфреймов. Другой подход - использование свойства document.readyState для проверки, загружен ли документ уже в момент выполнения скрипта. Современный JavaScript также предлагает метод await import() с динамическими импортами для более сложных сценариев.

Содержание

Событие DOMContentLoaded

Простейший и самый надежный способ воспроизвести функциональность jQuery’s $(document).ready() - использование события DOMContentLoaded. Это событие срабатывает, когда начальный HTML-документ полностью загружен и обработан, без ожидания завершения загрузки таблиц стилей, изображений и подфреймов.

javascript
document.addEventListener('DOMContentLoaded', function() {
    // Ваш код здесь
    console.log('DOM готов');
});

Этот подход широко поддерживается всеми современными браузерами и обеспечивает точно такое же время срабатывания, как метод ready() jQuery. Основное преимущество заключается в том, что он не требует внешних библиотек и нatively поддерживается браузером.

Важно: В отличие от window.onload, DOMContentLoaded не ожидает загрузки внешних ресурсов, таких как CSS-файлы, изображения или iframe, что именно то, что нужно при замене $(document).ready().

Проверка состояния документа

Для скриптов, которые могут выполняться до полной загрузки DOM, можно проверить свойство document.readyState. Этот подход особенно полезен, когда вы не можете контролировать, где скрипт размещен в документе.

javascript
// Проверяем, загружен ли документ уже
if (document.readyState === 'loading') {
    // Все еще загружается, ждем DOMContentLoaded
    document.addEventListener('DOMContentLoaded', function() {
        // Ваш код здесь
    });
} else {
    // DOMContentLoaded уже сработал
    // Ваш код здесь
}

Свойство readyState может принимать три значения:

  • ‘loading’: документ все еще загружается
  • ‘interactive’: документ полностью загружен и обработан, но подресурсы, такие как скрипты, изображения, таблицы стилей и фреймы, все еще загружаются
  • ‘complete’: документ и все подресурсы завершили загрузку

Этот метод гарантирует, что ваш код выполнится немедленно, если DOM уже готов, или дождется его, если он все еще загружается.

Современные подходы JavaScript

Современный JavaScript предлагает несколько элегантных способов обработки функциональности “DOM ready”:

Использование IIFE (Immediately Invoked Function Expression)

javascript
(function() {
    'use strict';
    
    if (document.readyState === 'complete' || 
        document.readyState === 'interactive') {
        // Документ уже готов
        initializeApp();
    } else {
        // Ждем DOMContentLoaded
        document.addEventListener('DOMContentLoaded', initializeApp);
    }
    
    function initializeApp() {
        // Ваш код инициализации здесь
        console.log('Приложение инициализировано');
    }
})();

Подход на основе Promise

javascript
function documentReady() {
    return new Promise(resolve => {
        if (document.readyState !== 'loading') {
            return resolve();
        }
        document.addEventListener('DOMContentLoaded', () => resolve());
    });
}

// Использование
documentReady().then(() => {
    // Ваш код здесь
    console.log('DOM готов');
});

Синтаксис async/await (ES2017+)

javascript
async function waitForDOMReady() {
    if (document.readyState === 'loading') {
        await new Promise(resolve => {
            document.addEventListener('DOMContentLoaded', resolve);
        });
    }
}

// Использование
waitForDOMReady().then(() => {
    // Ваш код здесь
    console.log('DOM готов');
});

Вопросы совместимости

Хотя DOMContentLoaded хорошо поддерживается в современных браузерах, для очень старых браузеров могут потребоваться запасные варианты:

Решение с кросс-браузерной совместимостью

javascript
function ready(callback) {
    // Для современных браузеров
    if (document.readyState !== 'loading') {
        callback();
    } else if (document.addEventListener) {
        // Стандартные браузеры
        document.addEventListener('DOMContentLoaded', callback);
    } else {
        // Старые браузеры IE
        document.attachEvent('onreadystatechange', function() {
            if (document.readyState === 'complete') {
                callback();
            }
        });
    }
}

// Использование
ready(function() {
    // Ваш код здесь
    console.log('DOM готов');
});

Это решение обрабатывает:

  • Современные браузеры с использованием DOMContentLoaded
  • Internet Explorer с использованием onreadystatechange
  • Случаи, когда скрипт выполняется после готовности DOM

Полные примеры реализации

Простая замена jQuery Ready

javascript
// Создаем простую функцию, похожую на jQuery ready
function ready(fn) {
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', fn);
    } else {
        fn();
    }
}

// Использование
ready(function() {
    console.log('Документ готов');
    
    // Теперь можно безопасно манипулировать DOM
    const elements = document.querySelectorAll('.my-class');
    elements.forEach(el => {
        el.style.color = 'blue';
    });
});

Расширенная функция, похожая на jQuery Ready

javascript
// Более комплексная функция, похожая на jQuery ready
const $ = {
    ready: function(callback) {
        // Обрабатываем случаи, когда DOM уже загружен
        if (document.readyState === 'interactive' || 
            document.readyState === 'complete') {
            // Используем setTimeout, чтобы обеспечить асинхронность callback
            return setTimeout(callback, 0);
        }
        
        // Используем DOMContentLoaded для современных браузеров
        if (document.addEventListener) {
            document.addEventListener('DOMContentLoaded', callback);
        } else {
            // Запасной вариант для старых браузеров
            document.attachEvent('onreadystatechange', function() {
                if (document.readyState === 'complete') {
                    callback();
                }
            });
        }
    }
};

// Использование
$.ready(function() {
    console.log('Документ готов, используется синтаксис, похожий на jQuery');
    
    // Ваш код манипуляции DOM здесь
    document.getElementById('my-element').textContent = 'Привет, мир';
});

Поддержка нескольких обработчиков Ready

javascript
// Поддержка нескольких обработчиков ready
const readyHandlers = [];
let isReady = false;

function onDocumentReady(handler) {
    if (isReady) {
        handler();
    } else {
        readyHandlers.push(handler);
    }
}

// Настраиваем слушатель DOMContentLoaded
if (document.addEventListener) {
    document.addEventListener('DOMContentLoaded', function() {
        isReady = true;
        readyHandlers.forEach(handler => handler());
    });
} else {
    document.attachEvent('onreadystatechange', function() {
        if (document.readyState === 'complete') {
            isReady = true;
            readyHandlers.forEach(handler => handler());
        }
    });
}

// Использование
onDocumentReady(function() {
    console.log('Первый обработчик выполнен');
});

onDocumentReady(function() {
    console.log('Второй обработчик выполнен');
});

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

При реализации собственного аналога $(document).ready учитывайте эти оптимизации производительности:

1. Используйте делегирование событий для динамического контента

javascript
ready(function() {
    // Используйте делегирование событий вместо привязки событий к отдельным элементам
    document.addEventListener('click', function(e) {
        if (e.target.matches('.dynamic-button')) {
            // Обработка кликов по динамическим кнопкам
            console.log('Нажата динамическая кнопка');
        }
    });
});

2. Минимизируйте операции с DOM

javascript
ready(function() {
    // Кэшируйте DOM-элементы, чтобы избежать повторных запросов
    const elements = {
        container: document.getElementById('main-container'),
        buttons: document.querySelectorAll('.action-button'),
        input: document.getElementById('user-input')
    };
    
    // Используйте кэшированные элементы
    elements.container.appendChild(document.createElement('div'));
});

3. Используйте requestAnimationFrame для визуальных обновлений

javascript
ready(function() {
    function updateUI() {
        // Выполняйте визуальные обновления
        requestAnimationFrame(updateUI);
    }
    
    requestAnimationFrame(updateUI);
});

4. Ленивая загрузка некритических ресурсов

javascript
ready(function() {
    // Загружайте некритические скрипты после готовности DOM
    const script = document.createElement('script');
    script.src = 'non-critical-script.js';
    script.defer = true;
    document.head.appendChild(script);
});

Источники

  1. MDN Web Docs - DOMContentLoaded Event
  2. MDN Web Docs - Document.readyState
  3. Stack Overflow - Document ready without jQuery
  4. JavaScript.info - DOMContentLoaded, load, beforeunload
  5. Can I Use - DOMContentLoaded Support

Заключение

Реализация $(document).ready без jQuery проста с использованием нативных событий JavaScript и свойств. Событие DOMContentLoaded предоставляет наиболее надежное и широко поддерживаемое решение, которое точно соответствует времени срабатывания jQuery. Для современного JavaScript-разработки рассмотрите использование подходов на основе Promise или синтаксиса async/await для более чистого кода. Всегда учитывайте совместимость браузеров при работе со старыми браузерами, которые могут не поддерживать современные события. Помните, что эти нативные подходы более производительны, чем реализация jQuery, поскольку они не имеют накладных расходов самой библиотеки jQuery.