Отказ от jQuery: нативные события DOM для современной разработки
Для кого эта статья:
- Веб-разработчики, ищущие оптимизацию кода и производительности своих проектов
- Студенты и обучающиеся программированию, желающие улучшить навыки работы с нативным JavaScript
Специалисты по оптимизации скорости загрузки сайтов, заинтересованные в современных методах и лучших практиках
Каждую неделю какой-нибудь фреймворк или библиотека прощается с нами, но jQuery продолжает цепляться за жизнь в тысячах проектов. Особенно прочно засел в памяти разработчиков знаменитый
$(document).ready()— такой удобный способ дождаться загрузки DOM. Но зачем тащить 30+ КБ кода ради одной функции? Пора взглянуть правде в глаза: нативный JavaScript давно решил эту проблему более элегантно и производительно. ИDOMContentLoaded— лишь верхушка айсберга возможностей, о которых многие до сих пор не подозревают. 🚀
Осваивая альтернативы jQuery
$.ready()в рамках Обучения веб-разработке от Skypro, вы не просто изучите современный синтаксис — вы перейдёте на новый уровень понимания процессов загрузки страницы. Наши студенты уменьшают размер своих проектов на 30-40%, а время загрузки — на 20-25%, просто заменяя устаревшие jQuery-конструкции на оптимизированные нативные решения. Присоединяйтесь к экспертам, которые не просто следуют трендам, а определяют их.
DOMContentLoaded: основная альтернатива jQuery.ready()
Событие DOMContentLoaded — это именно то событие, на котором базируется работа jQuery.ready(). Оно срабатывает, когда браузер полностью загрузил HTML и построил DOM-дерево, но ещё до того, как загрузились внешние ресурсы вроде изображений или стилей. По сути, это именно то, что нам нужно в большинстве случаев — возможность манипулировать DOM-элементами сразу, как только они становятся доступными.
Вместо громоздкого:
$(document).ready(function() {
// Код, который выполнится после загрузки DOM
});
Мы можем использовать лаконичный нативный JavaScript:
document.addEventListener('DOMContentLoaded', function() {
// Код, который выполнится после загрузки DOM
});
Преимущества DOMContentLoaded над jQuery.ready() очевидны:
- Отсутствие зависимостей — не нужно подключать тяжеловесную библиотеку
- Скорость выполнения — нативный код всегда работает быстрее библиотечного
- Меньший размер итогового JavaScript-кода — сокращение до 30+ КБ
- Более гибкий контроль — возможность более точно управлять жизненным циклом событий
Для удобства сравним производительность обоих подходов:
| Характеристика | jQuery.ready() | DOMContentLoaded |
|---|---|---|
| Дополнительный вес | ≈30-90 КБ (зависит от версии jQuery) | 0 КБ |
| Время инициализации | Медленнее (требуется загрузка и парсинг библиотеки) | Мгновенно |
| Поддержка браузерами | Требует полифилов для устаревших браузеров | IE9+, все современные браузеры |
| Дополнительные возможности | Встроенная обработка краевых случаев | Минимализм, требует ручной обработки |
Максим Дорофеев, технический директор Один из наших крупных клиентов жаловался на медленную загрузку своего интернет-магазина, особенно на мобильных устройствах. После аудита мы обнаружили, что 70% времени начальной загрузки уходило на jQuery и плагины к нему. При этом из всей библиотеки активно использовались лишь несколько функций, включая
$.ready().Мы заменили все вызовы
jQuery.ready()на обработчикиDOMContentLoaded, а затем постепенно избавились от остальных jQuery-зависимостей. Результат превзошел ожидания: время загрузки на мобильных устройствах сократилось на 47%, показатель отказов снизился на 18%, а конверсия выросла на 7.5%.Клиент был настолько впечатлен, что полностью переписал фронтенд своего приложения на нативный JavaScript в течение следующих 3 месяцев. Это был переломный момент, который убедил меня в том, что даже небольшие оптимизации могут дать существенные бизнес-результаты.

Как работает window.onload и чем отличается от $.ready()
Событие window.onload — еще один способ реагировать на загрузку страницы, но с критическим отличием от DOMContentLoaded и jQuery.ready(): оно срабатывает только после полной загрузки всех ресурсов страницы, включая изображения, стили, скрипты и другие внешние файлы. 📦
Вот как используется window.onload:
// Старый синтаксис (не рекомендуется)
window.onload = function() {
// Код выполнится только когда загрузятся ВСЕ ресурсы
};
// Современный подход с addEventListener
window.addEventListener('load', function() {
// Код выполнится только когда загрузятся ВСЕ ресурсы
});
Ключевые различия между этими событиями лучше представить в виде сравнительной таблицы:
| Событие | Момент срабатывания | Ожидает загрузки изображений | Ожидает загрузки CSS | Типичное применение |
|---|---|---|---|---|
jQuery.ready() | После построения DOM-дерева | Нет | Нет* | Манипуляции с DOM до отображения |
DOMContentLoaded | После построения DOM-дерева | Нет | Нет* | Начальная инициализация интерфейса |
window.onload | После загрузки всех ресурсов | Да | Да | Операции, требующие доступа ко всем ресурсам |
jQuery.ready()иDOMContentLoadedожидают загрузки CSS-файлов, только если они блокируют построение DOM, например, при использовании@importв CSS.
В каких ситуациях правильнее использовать window.onload, а не DOMContentLoaded?
- Когда работа требует доступа к загруженным изображениям — например, при необходимости получить размеры изображений или применить фильтры
- При взаимодействии с iframe, когда требуется удостовериться, что содержимое полностью загружено
- Для запуска аналитики полной загрузки страницы — метрики, связанные с производительностью
- При работе с видео-контентом, когда важно знать, что все медиа-файлы доступны
При этом нужно помнить, что чрезмерное использование window.onload может сильно замедлить интерактивность вашего сайта — пользователю придется ждать загрузки всего контента, прежде чем сможет взаимодействовать с интерфейсом.
Современные подходы к обработке загрузки DOM
Современный JavaScript предлагает более продвинутые и гибкие подходы к управлению жизненным циклом загрузки страницы, выходящие за рамки простой замены jQuery.ready(). 🛠️
Одним из таких подходов является использование более специализированных событий и методов:
// Отложенное выполнение без блокировки отображения страницы
document.addEventListener('readystatechange', event => {
if (document.readyState === 'interactive') {
// DOM готов, но ресурсы еще загружаются
} else if (document.readyState === 'complete') {
// Страница полностью загружена
}
});
// Асинхронная инициализация с Promise
function domReady() {
return new Promise(resolve => {
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', resolve);
} else {
resolve();
}
});
}
// Использование с async/await
async function init() {
await domReady();
console.log('DOM готов, начинаем работу!');
}
Особенно элегантным решением является использование механизма промисов и async/await, что позволяет создавать более читаемый и поддерживаемый код:
Алексей Семёнов, фронтенд-архитектор Один случай из моей практики запомнился особенно ярко. Мы работали над крупным приложением для обработки финансовой информации, где критически важным было быстрое время отклика интерфейса. Приложение использовало jQuery и ещё десяток различных библиотек, которые загружались последовательно.
Анализируя поведение системы, я обнаружил, что
jQuery.ready()дожидался загрузки основного DOM, но затем приложению всё равно приходилось ожидать асинхронного получения данных с бэкенда и инициализации других компонентов. Это создавало впечатление "дёрганого" интерфейса.Мы полностью переработали архитектуру загрузки приложения, заменив
jQuery.ready()на систему промисов и декларативную спецификацию зависимостей:JSСкопировать кодconst domReady = new Promise(resolve => { document.addEventListener('DOMContentLoaded', resolve); }); const dataReady = fetch('/api/initial-data').then(r => r.json()); Promise.all([domReady, dataReady]).then(([_, data]) => { initializeApp(data); });Эта простая замена позволила параллелизировать загрузку данных и DOM, сократив время до полной интерактивности приложения на 40%. Пользователи даже начали спрашивать, не обновили ли мы оборудование на серверах!
Современные фреймворки также предлагают свои подходы к решению проблемы инициализации после загрузки DOM:
- React с
useEffect()— хук, который позволяет выполнять код после рендеринга компонента - Vue с
mounted()— хук жизненного цикла, срабатывающий после монтирования компонента - Angular с
ngAfterViewInit— интерфейс, предоставляющий метод, вызываемый после инициализации представления - Svelte с
onMount— функция, выполняемая при монтировании компонента
Что действительно разумно в современных проектах — это декомпозиция инициализации на отдельные этапы:
- Критический рендеринг — минимальная функциональность, необходимая для первого взаимодействия с пользователем
- Основная функциональность — загрузка после
DOMContentLoaded - Отложенная функциональность — загрузка по мере необходимости, с использованием
IntersectionObserverилиrequestIdleCallback - Дополнительные возможности — загрузка по запросу пользователя
Практические решения для различных браузеров
Хотя современные браузеры отлично поддерживают DOMContentLoaded и другие события жизненного цикла страницы, в реальных проектах часто приходится учитывать особенности различных браузеров и их версий. 🔄
Универсальное кроссбраузерное решение, которое надежно работает во всех средах:
function onDocumentReady(callback) {
// Современные браузеры
if (document.readyState !== 'loading') {
setTimeout(callback, 0);
} else if (document.addEventListener) {
document.addEventListener('DOMContentLoaded', callback);
} else {
// IE8 и более старые версии
document.attachEvent('onreadystatechange', function() {
if (document.readyState === 'complete') {
callback();
}
});
}
}
// Использование
onDocumentReady(function() {
console.log('DOM готов!');
});
Данная функция последовательно проверяет различные способы определения готовности DOM:
- Сначала проверяется, не загрузился ли DOM уже к моменту вызова функции
- Если DOM еще загружается и браузер поддерживает
addEventListener, используетсяDOMContentLoaded - Для устаревших браузеров (IE8 и старше) используется событие
onreadystatechangeи проверкаreadyState
Для более сложных сценариев можно рассмотреть специфичные решения для различных типов браузеров:
| Браузер/Платформа | Проблема | Решение |
|---|---|---|
| Internet Explorer <= 8 | Не поддерживает DOMContentLoaded | Использовать onreadystatechange и document.readyState |
| Старые мобильные браузеры | Непоследовательная работа событий загрузки | Комбинировать проверку readyState и setTimeout |
| Safari на iOS | Задержка событий при загрузке внешних ресурсов | Использовать requestAnimationFrame для критических операций |
| Современные браузеры | Потребность в асинхронной загрузке модулей | Использовать import() и динамическую загрузку компонентов |
Важно учитывать и особые случаи, которые могут влиять на правильное срабатывание событий:
- Динамически генерируемые скрипты — могут вызывать повторные
DOMContentLoadedв некоторых ситуациях - Shadow DOM и веб-компоненты — имеют свой жизненный цикл, независимый от основного DOM
- Ресурсы, загружаемые через ServiceWorker — могут влиять на последовательность срабатывания событий
- iframe и вложенные документы — имеют собственные события
DOMContentLoaded, не связанные с родительским документом
Рациональной стратегией остаётся использование прогрессивного улучшения: сначала обеспечьте базовую функциональность, которая работает везде, а затем постепенно добавляйте продвинутые возможности для современных браузеров.
Оптимизация скорости загрузки без jQuery
Отказ от jQuery в пользу нативных решений — лишь первый шаг к оптимизации скорости загрузки. Комплексный подход требует переосмысления всей стратегии загрузки ресурсов и исполнения JavaScript. ⚡️
Вот ключевые принципы оптимизации, которые следует применять вместе с заменой jQuery.ready():
- Минимизация блокирующего JavaScript — перемещение скриптов в конец body или использование атрибутов
async/defer - Разделение кода на критический и некритический — первый загружается сразу, второй — после
DOMContentLoaded - Ленивая загрузка компонентов — инициализация только видимых элементов с
IntersectionObserver - Приоритизация основного потока — разбиение тяжелых вычислений с помощью
requestAnimationFrameиrequestIdleCallback
Пример стратегии прогрессивной загрузки:
// Критически важный JavaScript – встраиваем прямо в HTML
document.addEventListener('DOMContentLoaded', () => {
// Основная инициализация после загрузки DOM
initApp();
// Запрашиваем некритичные ресурсы с низким приоритетом
requestIdleCallback(() => {
loadNonCriticalFeatures();
});
// Подгружаем контент при прокрутке
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
lazyLoadComponent(entry.target);
observer.unobserve(entry.target);
}
});
});
document.querySelectorAll('.lazy-component').forEach(el => {
observer.observe(el);
});
});
function initApp() {
// Инициализация основного функционала
}
async function loadNonCriticalFeatures() {
// Динамический импорт некритичных модулей
const { setupAnalytics } = await import('./analytics.js');
setupAnalytics();
}
async function lazyLoadComponent(element) {
const componentType = element.dataset.component;
const { initializeComponent } = await import(`./components/${componentType}.js`);
initializeComponent(element);
}
Сравнение эффективности различных подходов к загрузке страницы:
| Подход | Время до интерактивности | Размер загружаемого JS | Влияние на CLS |
|---|---|---|---|
jQuery с $(document).ready() | Среднее (1000-1500 мс) | Высокий (100-200 КБ) | Среднее |
DOMContentLoaded + полная загрузка всех скриптов | Ниже среднего (800-1200 мс) | Средний (50-100 КБ) | Среднее |
| Критический CSS + отложенный JavaScript | Низкое (400-700 мс) | Низкий при начальной загрузке (10-30 КБ) | Низкое |
| Стратегия прогрессивной загрузки | Очень низкое (200-500 мс) | Минимальный при начальной загрузке (5-15 КБ) | Минимальное |
Помимо оптимизации JavaScript, следует уделить внимание и другим аспектам:
- Вставка критического CSS непосредственно в HTML — устраняет блокирующие запросы
- Предварительная загрузка ключевых ресурсов с помощью
<link rel="preload"> - HTTP/2 мультиплексирование — эффективная загрузка нескольких ресурсов одновременно
- Кэширование с помощью Service Worker — мгновенная загрузка при повторных посещениях
Используя эти техники вместе с правильным применением DOMContentLoaded и других событий жизненного цикла, вы можете значительно сократить время до взаимодействия (TTI) и улучшить восприятие скорости загрузки вашего приложения.
Переход от
jQuery.ready()к нативным событиям жизненного цикла DOM — не просто замена синтаксиса, а фундаментальное изменение подхода к разработке. Отказ от тяжеловесных библиотек в пользу специализированных решений позволяет полностью контролировать процесс загрузки и исполнения кода. Результат такой трансформации превосходит ожидания: сайты становятся не просто быстрее на 30-50%, но и более отзывчивыми, предсказуемыми и устойчивыми к проблемам соединения. В мире, где каждая миллисекунда загрузки напрямую влияет на конверсию, подобная оптимизация — не роскошь, а необходимость для конкурентного преимущества.