Как реализовать эквивалент $(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
- Проверка состояния документа
- Современные подходы JavaScript
- Вопросы совместимости
- Полные примеры реализации
- Лучшие практики производительности
Событие DOMContentLoaded
Простейший и самый надежный способ воспроизвести функциональность jQuery’s $(document).ready() - использование события DOMContentLoaded. Это событие срабатывает, когда начальный HTML-документ полностью загружен и обработан, без ожидания завершения загрузки таблиц стилей, изображений и подфреймов.
document.addEventListener('DOMContentLoaded', function() {
// Ваш код здесь
console.log('DOM готов');
});
Этот подход широко поддерживается всеми современными браузерами и обеспечивает точно такое же время срабатывания, как метод ready() jQuery. Основное преимущество заключается в том, что он не требует внешних библиотек и нatively поддерживается браузером.
Важно: В отличие от window.onload, DOMContentLoaded не ожидает загрузки внешних ресурсов, таких как CSS-файлы, изображения или iframe, что именно то, что нужно при замене $(document).ready().
Проверка состояния документа
Для скриптов, которые могут выполняться до полной загрузки DOM, можно проверить свойство document.readyState. Этот подход особенно полезен, когда вы не можете контролировать, где скрипт размещен в документе.
// Проверяем, загружен ли документ уже
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)
(function() {
'use strict';
if (document.readyState === 'complete' ||
document.readyState === 'interactive') {
// Документ уже готов
initializeApp();
} else {
// Ждем DOMContentLoaded
document.addEventListener('DOMContentLoaded', initializeApp);
}
function initializeApp() {
// Ваш код инициализации здесь
console.log('Приложение инициализировано');
}
})();
Подход на основе Promise
function documentReady() {
return new Promise(resolve => {
if (document.readyState !== 'loading') {
return resolve();
}
document.addEventListener('DOMContentLoaded', () => resolve());
});
}
// Использование
documentReady().then(() => {
// Ваш код здесь
console.log('DOM готов');
});
Синтаксис async/await (ES2017+)
async function waitForDOMReady() {
if (document.readyState === 'loading') {
await new Promise(resolve => {
document.addEventListener('DOMContentLoaded', resolve);
});
}
}
// Использование
waitForDOMReady().then(() => {
// Ваш код здесь
console.log('DOM готов');
});
Вопросы совместимости
Хотя DOMContentLoaded хорошо поддерживается в современных браузерах, для очень старых браузеров могут потребоваться запасные варианты:
Решение с кросс-браузерной совместимостью
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
// Создаем простую функцию, похожую на 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
// Более комплексная функция, похожая на 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
// Поддержка нескольких обработчиков 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. Используйте делегирование событий для динамического контента
ready(function() {
// Используйте делегирование событий вместо привязки событий к отдельным элементам
document.addEventListener('click', function(e) {
if (e.target.matches('.dynamic-button')) {
// Обработка кликов по динамическим кнопкам
console.log('Нажата динамическая кнопка');
}
});
});
2. Минимизируйте операции с DOM
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 для визуальных обновлений
ready(function() {
function updateUI() {
// Выполняйте визуальные обновления
requestAnimationFrame(updateUI);
}
requestAnimationFrame(updateUI);
});
4. Ленивая загрузка некритических ресурсов
ready(function() {
// Загружайте некритические скрипты после готовности DOM
const script = document.createElement('script');
script.src = 'non-critical-script.js';
script.defer = true;
document.head.appendChild(script);
});
Источники
- MDN Web Docs - DOMContentLoaded Event
- MDN Web Docs - Document.readyState
- Stack Overflow - Document ready without jQuery
- JavaScript.info - DOMContentLoaded, load, beforeunload
- Can I Use - DOMContentLoaded Support
Заключение
Реализация $(document).ready без jQuery проста с использованием нативных событий JavaScript и свойств. Событие DOMContentLoaded предоставляет наиболее надежное и широко поддерживаемое решение, которое точно соответствует времени срабатывания jQuery. Для современного JavaScript-разработки рассмотрите использование подходов на основе Promise или синтаксиса async/await для более чистого кода. Всегда учитывайте совместимость браузеров при работе со старыми браузерами, которые могут не поддерживать современные события. Помните, что эти нативные подходы более производительны, чем реализация jQuery, поскольку они не имеют накладных расходов самой библиотеки jQuery.