Веб-разработка
DOM и браузерные API
2004 год. Google Maps запускается. Весь картографический рынок в шоке: карты двигаются без перезагрузки страницы. Под капотом - XMLHttpRequest и интенсивные DOM манипуляции. Этот момент определил архитектуру веба на следующие 20 лет.
- **React Virtual DOM:** абстракция над DOM API, batch updates и minimal reflows - причина популярности. React DOM diffing экономит 10-100x reflow операций на сложных UI
- **Service Workers + Cache API:** Progressive Web Apps кэшируют fetch-запросы для offline работы. Twitter Lite работает при скорости 2G через aggressive caching
- **ResizeObserver, IntersectionObserver:** современные браузерные API без polling. Infinite scroll, lazy loading изображений, responsive компоненты - без setTimeout интервалов
Исторический контекст
В 1998 году Алекс Хопманн из Microsoft разработал XMLHttpRequest как ActiveX компонент для Outlook Web Access - первого корпоративного webmail. Mozilla реализовала нативный XHR в 2002. Google использовала XHR в Gmail (2004) и Google Maps (2005). Этот паттерн назвали AJAX (Asynchronous JavaScript and XML) - термин предложен Джесси Джеймс Гарретом в 2005. Fetch API появился в 2015 как современная замена XHR. DOM Level 1 стандартизован W3C в 1998, Virtual DOM изобретён командой React в 2013.
DOM: структура, парсинг и layout reflow
**2004 год. Gmail запускается. Для 2004-го это шок: веб-приложение которое работает как десктопное - без перезагрузки страницы.** Секрет - JavaScript манипуляция DOM (Document Object Model). DOM - дерево объектов, представляющих HTML. Браузер парсит HTML в DOM tree, применяет CSS (CSSOM), объединяет в Render Tree, вычисляет layout (размеры и позиции) и рисует (paint). Любая манипуляция DOM потенциально запускает этот цикл заново.
**Critical Rendering Path:** HTML -> DOM -> CSSOM -> Render Tree -> Layout -> Paint -> Composite. JavaScript блокирует парсинг HTML (если нет defer/async). Изменение `width` или `display` запускает Layout (дорого). Изменение `color` или `opacity` - только Paint (дешевле). Изменение `transform` или `opacity` через CSS animation - только Composite (дёшево, GPU-accelerated).
Какой CSS property выгоднее анимировать для плавности: `left/top` или `transform: translate()`?
Events: bubbling, capturing и делегирование
**Event propagation в DOM - одна из самых частых причин багов у начинающих.** Когда кликаешь на кнопку внутри div - событие распространяется в двух фазах: capturing (от window вниз к цели) и bubbling (от цели вверх к window). addEventListener принимает третий параметр: `true` = capturing фаза, `false` (default) = bubbling. Это позволяет перехватывать события на родительских элементах - Event Delegation.
**Memory leaks через event listeners:** если DOM-элемент удаляется но listener остаётся - утечка памяти. Решение: removeEventListener при удалении элемента или использование AbortController. В React/Vue это автоматически - framework управляет lifecycle.
Список из 10 000 элементов. Какой подход к event handling правильный?
Fetch API и async/await: HTTP-запросы в браузере
**XMLHttpRequest (XHR) - API 1999 года, придуманный командой Microsoft для Outlook Web Access.** Callback hell из вложенных обработчиков. Fetch API (2015) заменил XHR: Promise-based, чистый синтаксис, поддержка async/await. С 2022: встроен в Node.js. Fetch - стандарт для браузерных HTTP запросов.
**CORS (Cross-Origin Resource Sharing):** браузер блокирует fetch к другому origin (домен, порт, протокол). Сервер должен вернуть заголовок `Access-Control-Allow-Origin: *` или конкретный origin. Preflight: браузер сначала отправляет OPTIONS запрос для 'unsafe' методов (DELETE, PUT) и custom headers. CORS - браузерная защита, не серверная: curl игнорирует его.
Fetch возвращает Response с status 404. Попадёт ли выполнение в catch блока?
Браузерное хранилище: cookies, localStorage, IndexedDB
**2009 год. HTML5 Web Storage API.** До этого единственный способ хранить данные в браузере - cookies (4 KB, отправляются с каждым запросом). localStorage/sessionStorage: 5-10 MB, синхронные, только строки. IndexedDB: гигабайты, асинхронный, structured data. Cache API (Service Workers): кэш сетевых ответов для offline.
| Storage | Лимит | Асинхронный | Отправляется с запросами | Использование |
|---|---|---|---|---|
| cookie | 4 KB | Нет | Да | Auth tokens, tracking (HttpOnly) |
| localStorage | 5-10 MB | Нет | Нет | User preferences, app state |
| sessionStorage | 5-10 MB | Нет | Нет | Временные данные формы |
| IndexedDB | ~1 GB+ | Да | Нет | Offline data, файлы, кэш |
| Cache API | Гибко | Да | Нет | Service Worker, offline стратегии |
localStorage безопасен для хранения токенов потому что нельзя прочитать из другого домена
localStorage изолирован по origin (Same-Origin Policy), но уязвим к XSS атакам: любой JS-код на странице (включая вредоносный из CDN или через XSS) читает localStorage.
XSS (Cross-Site Scripting) - одна из топ-5 уязвимостей OWASP. Если в приложении есть XSS, атакующий выполняет `document.cookie` (без HttpOnly) или `localStorage.getItem('token')`. HttpOnly cookie недоступен для JavaScript - это ключевое отличие. Для production: refresh token в HttpOnly cookie + SameSite=Strict.
Нужно сохранить JWT access token (короткоживущий) и refresh token (долгоживущий) в браузере. Где хранить каждый?
DOM и браузерные API: главное
- DOM manipulation: batch updates через DocumentFragment или innerHTML. Каждый отдельный insert запускает reflow
- Event bubbling: события всплывают от target к document. Event Delegation - один listener на родителе вместо N на детях
- Fetch: Promise-based HTTP. Не кидает ошибку при 4xx/5xx - проверять response.ok явно. AbortController для timeout
- Storage: localStorage (5MB, синхронный) vs IndexedDB (гигабайты, асинхронный). JWT в HttpOnly cookie, не localStorage
- CSS animation через transform/opacity - GPU composite. left/top - Layout reflow - janky animations
Вопросы для размышления
- React использует Virtual DOM для оптимизации DOM манипуляций. Но инициализация React занимает 200-400 КБ JS и дополнительное время parse/execution. Когда прямые DOM манипуляции без фреймворка будут быстрее чем React?