Браузер и фронтенд-рантайм
Задачи, микрозадачи и scheduler.yield()
Вы пишете await Promise.resolve(), чтобы «уступить» внутри длинного цикла. Браузер всё равно зависает. Пробуете setTimeout(fn, 0). Теперь мигает странно. Проблема не в коде — вы просто не знаете, в какую очередь попадает каждый примитив.
Модель HTML-спецификации: источники задач и очереди задач
HTML-стандарт (§ event loops) определяет event loop как поток с набором очередей задач. Каждая задача связана с источником задач — типом породившей её работы (манипуляции с DOM, пользовательские взаимодействия, сеть, навигация по истории). Каждый источник имеет собственную очередь, и пользовательский агент выбирает одну очередь за итерацию, вытягивает старейшую задачу и исполняет её до конца без прерываний. Когда задача завершается, агент выполняет microtask checkpoint, затем опционально шаг рендеринга, затем возвращается в начало.
Микрозадачи vs задачи: решающее правило
Микрозадача ставится в очередь: Promise.then, Promise.catch, Promise.finally, queueMicrotask, MutationObserver и await (синтаксический сахар над Promise.then).
Задача ставится в очередь: setTimeout, setInterval, MessageChannel.postMessage, сетевые ответы, отправленные DOM-события, распарсенные куски HTML.
Решающее операционное правило: микрозадачи дренируются до пустой между каждой задачей и каждым кадром. Если микрозадача планирует ещё одну микрозадачу, обе выполняются до того, как цикл перейдёт дальше. Именно поэтому Promise.resolve().then(self) в тесной цепочке вешает страницу: очередь микрозадач никогда не пуста, цикл никогда не доходит до шага 4, и браузер никогда не рисует.
- Promise.then / queueMicrotask
- очередь микрозадач
- setTimeout / setInterval
- очередь задач (источник таймеров)
- MessageChannel.postMessage
- очередь задач (источник сообщений)
- DOM-событие click
- очередь задач (источник пользовательского ввода)
- Колбэк MutationObserver
- очередь микрозадач
- scheduler.yield()
- очередь задач (возобновляется как следующая задача)
queueMicrotask vs Promise.resolve().then vs MessageChannel
Три способа «запланировать что-то скоро», каждый с разной семантикой:
queueMicrotask(fn)— ставит микрозадачу напрямую. Выполняется после текущей задачи, до следующей. Рендеринга между ними нет.Promise.resolve().then(fn)— идентична queueMicrotask по времени, но аллоцирует Promise, замыкание и элемент цепочки. Чуть медленнее, по сути то же самое. Рендереру не уступает.new MessageChannel().port1.postMessage(...)— ставит задачу. Выполняется после текущей задачи, после дренажа микрозадач, возможно после кадра. Уступает рендереру.
Это важно, когда нужно уступить рендерингу: микрозадачи не уступают; MessageChannel — уступает. Современный код использует scheduler.yield() (Chrome 115+) для явных точек уступки.
Где находится requestAnimationFrame
Колбэки rAF выполняются на шаге 4 цикла, непосредственно перед стилями/компоновкой/отрисовкой. Браузер входит в шаг 4 только когда решает, что кадр пора показать — обычно каждые 16,67 мс при 60 Гц. Если длинная задача пропустила несколько дедлайнов кадра, браузер не ставит несколько rAF-колбэков в очередь; он запускает rAF-набор ровно один раз. Вот почему длинная задача всегда выглядит как один пропущенный кадр: rAF управляется бюджетом рендеринга, а не таймером.
Где находится ввод
События ввода (mousemove, click, keydown, touchstart) ставятся в очередь как задачи потоком ввода браузера (отдельный поток ОС). Главный поток вытягивает их на шаге 1 как любую задачу. Прерываний нет: если ваша JS-задача выполняется 80 мс, а клик пришёл на отметке 20 мс, клик ждёт 60 мс до запуска обработчика. INP измеряет именно эту задержку: когда пользователь кликнул, когда следующая отрисовка отразила результат. INP < 200 мс p75 считается «хорошим». Достичь этого значит не допускать задач длиннее примерно 50 мс.
Как DOM-событие становится задачей
Когда пользователь кликает, поток ввода браузера записывает цель попадания и ставит единственную задачу в очередь задач источника пользовательских взаимодействий главного потока. Когда главный поток вытягивает эту задачу, он выполняет полный диспатч события за один раз: фаза захвата вниз к цели, затем сама цель, затем фаза всплытия обратно вверх. Все совпадающие слушатели вдоль этого пути выполняются синхронно внутри этой одной задачи — между ними нет точек уступки. Именно поэтому медленный слушатель на высоком предке (обработчик mousemove на document) нагружает каждое взаимодействие с потомком. Опция passive: true важна для scroll, wheel и touch: она обещает, что слушатель не вызовет preventDefault(), позволяя браузеру начать прокрутку на композиторе без ожидания окончания задачи диспатча.
Уступка внутри длинной задачи
Если нужно выполнить 200 мс работы, разбейте её на куски ≤50 мс, разделённые точками уступки, чтобы ввод мог вклиниваться. Три техники:
setTimeout(fn, 0)— ставит задачу примерно через 4 мс (зажато); грубо, но универсально.MessageChannelсpostMessage— ставит задачу немедленно, без зажима. Именно это использует React 18 внутри для time-slicing.scheduler.yield()(Chrome 115+) — обещает точку уступки, которая позволяет запустить ввод и рендеринг, затем возобновляет ту же логическую задачу с приоритетом. Современная рекомендация: используйтеscheduler.yield(), при недоступности —setTimeout(0). Не используйтеawait Promise.resolve()для уступки — это ставит микрозадачу, которая не позволяет запустить рендерер.
`setTimeout(fn, 0)` и `queueMicrotask(fn)` оба «планируют что-то скоро». В чём операционная разница?
Тело цикла: `await fetch(url)`. Почему страница всё равно рендерится между итерациями, хотя цикл никогда не возвращает управление?
DevTools Performance показывает «длинную задачу» 320 мс на обработчике поля поиска. INP страницы — 410 мс p75. Обработчик делает: парсит ввод → fetch подсказок → JSON.parse ответа → ре-рендер дропдауна. Где время?
Нужно разбить задачу 200 мс на куски по 50 мс, чтобы ввод мог вклиниваться. Какая техника реально позволяет браузеру обрабатывать ввод между кусками?
Worker вызывает `postMessage(data)` в главный поток. data — Float32Array 5 МБ. Что является доминирующей стоимостью?
Click-обработчик выполняет синхронный код, затем `Promise.resolve().then(...)`, затем `setTimeout(..., 0)`, затем ещё синхронный код. Расставьте колбэки в порядке их реального выполнения.
- 1 Синхронный код в начале обработчика
- 2 Синхронный код в конце обработчика (перед return)
- 3 Колбэк Promise.then (микрозадача)
- 4 Колбэк setTimeout (задача)
Когда два потока (главный и воркер) обмениваются данными, сообщения пересекаются через очередь задач, а не очередь микрозадач. Значит, нижняя граница задержки туда-обратно — одно переключение задачи в каждую сторону. Как это переключение обычно называют в обсуждениях производительности?
Нужно запланировать код «после этого синхронного блока, как можно скорее». Какой примитив?
Колбэк `setTimeout(fn, 0)` после 5-го уровня вложенности зажимается до минимума. По HTML-спецификации этот минимум (в мс) равен:
- 01Объясните, почему `await Promise.resolve()` не «уступает браузеру», хотя и приостанавливает вызывающую функцию.
- 02Воркер отправляет 60 сообщений в секунду в главный поток, каждое несёт небольшой JSON. Почему это всё равно вызывает джанк главного потока, даже если каждое сообщение крошечное?
- 03Почему медленный слушатель событий на `document` (например, обёртка аналитики для mousemove) нагружает каждое взаимодействие с потомком?
HTML-спецификация определяет несколько очередей задач — по одной на источник задач — и браузер выбирает одну очередь за итерацию. Микрозадачи, напротив, живут в едином checkpoint, который дренируется до пустой после каждой задачи и до каждого кадра. Три примитива планирования имеют разную семантику: queueMicrotask работает до рендеринга, setTimeout(0)/MessageChannel — после рендеринга (уступка на уровне задач), а scheduler.yield() — структурированная уступка уровня задач с сохранением приоритета. События ввода попадают в очередь задач из потока ввода ОС; задача длиной 80 мс задерживает пришедший в середине клик на всю оставшуюся длительность. Опция passive на слушателях scroll и touch позволяет потоку композитора начать немедленно вместо ожидания задачи диспатча — конкретный выигрыш для отзывчивости скролла без изменения JS-логики.
встречается в267
- Почему GraphQL получает N+1junior
- Механика DataLoader: батчинг на границе тикаmiddle
- Контракты batch-функции: порядок, формы, ошибкиmiddle
- Federation и lookahead: батчинг за пределами DataLoadermiddle
- Защита сложности запросов: depth, cost, persisted queriesmiddle
- Senior GraphQL API: scheduling-контракт, изоляция арендаторов, наблюдаемостьsenior
- Путь запроса: семь остановок от сокета до ответаjunior
- Accept и парсинг: от очереди ядра до типизированного запросаmiddle
- Маршрутизация и middleware: что выполняется и в каком порядкеmiddle
- Обработчик и ответ: от бизнес-логики до байтов на проводеmiddle
- Стриминг и backpressure: когда клиент читает медленнее, чем вы пишетеsenior
- Таймауты и хвостовая задержка: бюджеты, дедлайны и ловушка fan-outsenior
- Middleware и DI: два паттерна, формирующие любой backendjunior
- Пишем middleware: сигнатуры, next() и три модели фреймворковmiddle
- Инверсия управления: как зависимости добираются до классаmiddle
- Скоупы и время жизни DI: singleton, request, transientmiddle
- DI как шов для тестов: фейки, моки и граница, которая важнаsenior
- DI-контейнеры в продакшене: графы разрешения, циклы и когда не стоитsenior
- Блокирующий vs неблокирующий I/O: два способа ждатьjunior
- Event loop: один поток, упорядоченные фазыmiddle
- Что блокирует цикл: CPU-работа и синхронные вызовыmiddle
- Вынос CPU-работы: worker threads и пул libuvmiddle
- Backpressure и ограниченная конкурентностьsenior
- Пропускная способность под нагрузкой: хвостовая задержка и насыщениеsenior
- Зачем пул: цена создания соединенияjunior
- Размер пула: почему больше не значит быстрееmiddle
- Взятие и таймауты: очередь ожидания — настоящий дроссель задержкиmiddle
- Зачем идемпотентность: безопасные retryjunior
- Серверный state machine: четыре состояния idempotency keymiddle
- Стратегии retry: backoff, jitter и thundering herdmiddle
- Outbox и inbox: effectively-once через dual-write границуmiddle
- Конкурентность и архитектура кеша для идемпотентности на масштабеsenior
- Наблюдаемость, production-инциденты и дизайн для глобального масштабаsenior
- Что такое cache stampede и почему он делает всё хужеjunior
- Лок и single-flight: ограничение параллельных rebuildmiddle
- XFetch: вероятностное раннее истечение без координацииmiddle
- Stale-while-revalidate и CDN request coalescingmiddle
- Детектирование stampede и дизайн TTL для продакшенаmiddle
- Метастабильный сбой, fencing-токены и production-постмортемыsenior
- Что такое отношение: таблицы, строки, ключи и ограниченияjunior
- Ограничения, ключи и типы данных Postgresmiddle
- Нормальные формы, денормализация и почему схемы «прилипают»middle
- JSONB, массивы и когда side table побеждаетmiddle
- Heap-хранилище, TOAST и выравнивание колонокsenior
- Целостность схемы: deferral, версионирование и сбои в продакшнеsenior
- Реляционная модель vs документные, wide-column, граф и key-valuesenior
- Что такое индекс и как он ускоряет запросыjunior
- Leading-column rule: почему порядок столбцов в composite-индексе важенmiddle
- Partial, expression и covering-индексыmiddle
- Типы индексов: GIN, GiST, BRIN, Hash, Bloom и HOT-обновленияmiddle
- Index-only scan, Visibility Map и INCLUDEsenior
- Типичные сбои в продакшне и аудит индексовsenior
- Упражнение по проектированию индексов: стратегия полнотекстового поискаsenior
- EXPLAIN и планы выполнения: что решает планировщик и почемуjunior
- Типы сканирования: Seq, Index, Bitmap, Index-Onlymiddle
- Алгоритмы соединения и каскад ошибок оценки строкmiddle
- pg_statistic, ANALYZE и производственная наблюдаемостьmiddle
- Расширенная статистика: исправление ошибок оценки для коррелированных колонокsenior
- Кеш планов, настройка константных стоимостей и внутренности планировщикаsenior
- Производственные режимы отказа и стабильность плановsenior
- MVCC: как Postgres раздаёт согласованные снимкиjunior
- Заголовок tuple и механика снимковmiddle
- HOT-обновления и уровни изоляцииmiddle
- VACUUM, bloat и autovacuummiddle
- CLOG, XID wraparound и MultiXactsenior
- SSI и production-тюнинг autovacuumsenior
- Реальные провалы MVCC, deployment-паттерны и распределённые снимкиsenior
- Connection pool: зачем амортизировать стоимость backend Postgresjunior
- Режимы PgBouncer: session, transaction и statementmiddle
- Размер пула: формула (ядра × 2) + шпинделей и двухуровневый стекmiddle
- Исчерпание пула и idle-in-transaction: сценарий отказа в 3 ночиmiddle
- Миграция на transaction mode: план развёртывания и prepared statements в PgBouncer 1.21middle
- Процессная модель Postgres и почему увеличение max_connections снижает производительностьsenior
- Ландшафт пулеров 2026, serverless connection storms и полная таксономия отказовsenior
- Что такое миграция схемы и почему она заменяет ad-hoc DDLjunior
- ADD COLUMN: мгновенно в PG 11+ против перезаписи в старом Postgresjunior
- Режим отказа очереди блокировок: почему мгновенный DDL может заморозить базуmiddle
- Безопасные DDL-паттерны: NOT VALID, CONCURRENTLY и исправления небезопасных операцийmiddle
- Expand-contract: нулевой простой для ломающих изменений схемыmiddle
- Advisory-блокировки, инструменты миграций и координация деплояsenior
- Таксономия сбоев миграций и дисциплина продакшнаsenior
- Зачем нужно шардирование: потолок одного Postgresjunior
- Выбор ключа шарда: стратегии hash, range, list и directorymiddle
- Партиционирование против шардирования: одно слово, два разных понятияmiddle
- Ко-локация и Citus: инвариант, делающий шардирование пригодным к использованиюmiddle
- Режим отказа hot shard: обнаружение, изоляция и долгосрочная политикаmiddle
- Schema-based шардирование и альтернативы мультиарендностиsenior
- Онлайн-решардинг, 2PC и операционная стоимость шардированияsenior
- Семь актов: от CREATE TABLE до Citusjunior
- Акты 1–3 в глубину: схема, индексы и статистика планировщикаmiddle
- Акты 4–6 в глубину: MVCC bloat, connection pooling и безопасные миграцииmiddle
- Акт 7 в глубину: шардинг, co-location и семиуровневый каскад трейдоффовmiddle
- Наблюдаемость, антипаттерны и производственный триажsenior
- Роли Raft, term и почему majority-кворум предотвращает split brainjunior
- Как Raft реплицирует log entry и решает, что его безопасно коммититьmiddle
- Выборы лидера в Raft: таймауты, правила голосования и четыре свойства безопасностиmiddle
- Raft в реальном мире: partition, медленный диск и клиентская маршрутизацияmiddle
- Расширения Raft: pre-vote, learner, snapshot и линеаризуемые чтенияsenior
- Raft в production: membership change, Multi-Raft и observabilitysenior
- Где происходит data fetching — и почему это решает LCPjunior
- Fetch waterfall''''ы — диагностика и лечение через Promise.allmiddle
- React Server Components и Suspense streamingmiddle
- Клиентский кэш: TanStack Query, SWR и stale-while-revalidatemiddle
- LCP, prefetch и race conditions в интерактивном fetchingmiddle
- Senior internals: RSC payload, слои кэша и production паденияsenior
- Биты в проводеjunior
- Математика задержкиmiddle
- Bufferbloat и перегрузкаsenior
- Граница физического уровняsenior
- Трёхстороннее рукопожатие TCPjunior
- Номера последовательности и состояние соединенияmiddle
- Управление потоком и перегрузкойmiddle
- BBR, производственная наблюдаемость и за пределами TCPsenior
- DNS: что делает и зачем существуетjunior
- Обход резолвера: перенаправления, типы записей и gluemiddle
- TTL, кеширование и распространение DNSmiddle
- Рукопожатие за 1 RTT: key share и ECDHEmiddle
- Возобновление сессии и 0-RTTmiddle
- CDN: контент по соседствуjunior
- Anycast и GeoDNS: маршрутизация к ближайшему edgemiddle
- Многоуровневый кеш и Cache-Controlmiddle
- Заголовок Vary и cache keysmiddle
- Stale-while-revalidate и cache stampedesenior
- Edge workers и edge-side compositionsenior
- CDN: операции и observabilitysenior
- WebSocket: HTTP-апгрейд до постоянного соединенияjunior
- Формат WebSocket-фрейма: opcodes, маскирование, фрагментацияmiddle
- WebSocket vs SSE vs long-polling: выбор правильного транспортаmiddle
- Backpressure в WebSocket: когда клиенты не успеваютmiddle
- Реконнект: jittered backoff, thundering herd, восстановление сообщенийsenior
- WebSocket в масштабе: HTTP/2 мультиплексирование, permessage-deflate, C10Msenior
- WebSocket в production: прокси, безопасность и распределённая архитектураsenior
- Что делают обратные проксиjunior
- Алгоритмы балансировки: от round-robin до power-of-two-choicesmiddle
- L4 vs L7 балансировка и сохранение IP клиентаmiddle
- Health checks, connection draining и slow startmiddle
- Session affinity, consistent hashing и правильное решениеmiddle
- Retry-бури, circuit breakers и load sheddingsenior
- Устойчивая архитектура LB: anycast, zone-aware маршрутизация и observabilitysenior
- Почему QUIC, а не TCP+TLSjunior
- QUIC-потоки и head-of-line blockingjunior
- Объединённое рукопожатие и 1-RTTmiddle
- Connection ID и миграция сетиmiddle
- Обнаружение потерь и управление перегрузкойmiddle
- Возобновление 0-RTT и шифрование пакетовsenior
- Развёртывание и стоимость CPUsenior
- DDoS: что это и почему работаетjunior
- Атаки усиления и истощение состоянияmiddle
- Ограничение скорости: алгоритмы и архитектураmiddle
- WAF, межсетевые экраны, mTLS и HSTSmiddle
- Отравление DNS-кэша и BGP-перехватsenior
- Эшелонированная защита и экономика атакsenior
- Двенадцать слоёв: один URL, семь действующих лицjunior
- DNS, TCP, TLS по очереди: куда уходят миллисекундыmiddle
- Критический путь рендеринга и Core Web Vitalsmiddle
- Перехват прокси и шлюзы безопасности: rate limiter, WAF, mTLSmiddle
- Альтернативные пути: QUIC 0-RTT, WebSocket upgrade, миграция соединенияmiddle
- Наблюдаемость: распределённые трейсы, USE/RED и семплированиеsenior
- Устойчивость: каскадные повторы, circuit breakers и error budgetsenior
- Что такое три сигнала: метрики, логи, трейсыjunior
- Метрики и cardinality: cost-модель time-series databasemiddle
- Логи и объём: cost-модель структурного логированияmiddle
- Трейсы и сэмплирование: cost-модель distributed tracingmiddle
- Join-ключи и exemplar''''ы: как три сигнала становятся компонуемымиmiddle
- Observability 2.0: широкие события и сдвиг стоимостиsenior
- Режимы сбоя и инженерная практика: cardinality budget''''ы, PII и сэмплированиеsenior
- Зачем нужны структурные логи: дневник против таблицыjunior
- Схема продакшн-лога: поля, которые несёт каждая строкаmiddle
- Log levels и маршрутизация алертовmiddle
- Стратегии sampling и стоимость логовmiddle
- PII-редакция и log injectionsenior
- Propagation trace-контекста в логахsenior
- OTel Logs Data Model и audit-логи как подсистемаsenior
- Сигналы OTel, Semantic Conventions и проводной формат OTLPmiddle
- Авто-инструментирование и ручные спаны: правило 80/20 в OTelmiddle
- Collector OTel: receivers, processors, exporters и паттерны развёртыванияmiddle
- Стратегии сэмплирования: head, tail и parent-basedmiddle
- Vendor-нейтральность, eBPF-инструментирование, Operator и OTel в браузере и serverlesssenior
- Эксплуатация OTel Collector: надёжность, version skew, режимы отказа и управлениеsenior
- RED и USE: два чек-листа, одна дисциплина триажаjunior
- Инструментация RED в Prometheus: счётчики, гистограммы и дисциплина cardinalitymiddle
- USE на Linux: CPU, память, диск, сеть и PSImiddle
- Golden signals, структура дашборда и auto-RED в service meshmiddle
- Cardinality как драйвер затрат: label, PII, exemplars и семплированиеmiddle
- Native histograms, SLO и паттерны production-сбоевmiddle
- SLI, SLO и error budget: надёжность в числахjunior
- Выбор SLI и SLO-целей: отношения, не ощущенияmiddle
- Multi-window multi-burn-rate-алертинг: почему AND лучше ORmiddle
- Error budget policy, latency SLO и составные journeysmiddle
- Iceberg SLI, математика составного SLO и SLA vs SLOsenior
- Продакшн-отказы SLO, самонаблюдаемость, безопасность и общая картинаsenior
- Flame graph: читаем картинку, которая показывает, куда ушло времяjunior
- Sampling vs instrumentation profiling: почему 99 Гц побеждает в productionmiddle
- Типы профилей: CPU, память, off-CPU, mutex — какой когда братьmiddle
- Continuous profiling: always-on flame graphs с eBPF и корреляцией trace-idmiddle
- Как flame graph строится из сэмплов и как использовать его в productionmiddle
- Linux perf, внутренности eBPF, PGO и ограничения sampling''''аsenior
- Profiling в production: безопасность, war stories, OTel profiles и дизайн инфраструктурыsenior
- Debugging-воронка: SLO → RED → trace → profilejunior
- Архитектура OTel: один SDK, четыре сигнала, один wire-форматmiddle
- Экономия на observability: удерживаем затраты в пределах 5% inframiddle
- Петля инцидента: от пейджера до постмортема до предотвращенияmiddle
- Масштаб, безопасность и ROI наблюдаемых системsenior
- Сначала профиль: измерь куда реально уходит времяjunior
- Закон Амдала и self-time: потолок любого ускорения, которое ты можешь выпуститьmiddle
- Измерительный цикл: микробенч, макробенч, prod-профиль, эффект наблюдателяmiddle
- Чтение флейм-графов: формы, профайлеры по языкам и 60-секундный сканmiddle
- Статистические baseline''''ы: почему один запуск — не измерениеmiddle
- История профайлеров и ловушки микробенчей: от Кнута до GWPsenior
- Hardware counters, профили холодного старта и безопасность профилейsenior
- Непрерывное профилирование в масштабе: затраты, CI-гейты, корреляция с трейсами и антипаттерныsenior
- Что делает путь горячим: симптом против причиныjunior
- Пять форм hotspot''''а: CPU, аллокации, кэш, лок, syscallmiddle
- Чтение parent и child chains: где применять правкуmiddle
- JIT deopt, цикл fix-and-verify и PR-time профилированиеmiddle
- Аппаратные счётчики и Intel TMA: диагностика подкатегорийsenior
- False sharing и горячие пути нативных мостовsenior
- Горячие пути в production: безопасность, хвостовая латентность и происхождение инструментовsenior
- Иерархия памяти: почему расстояние важнее числа операцийjunior
- Row-major vs column-major: порядок доступа и разрыв в 9xjunior
- Cache lines и false sharing: когда параллелизм замедляет кодmiddle
- Branch prediction: 10–30 циклов штрафа за неожиданный ifmiddle
- SIMD и data layout: AoS vs SoA и разница в 4–8xmiddle
- Hardware prefetcher, TLB и memory-level parallelismsenior
- Cache-oblivious алгоритмы, PGO и production failuressenior
- Основы GC: за что рантайм берёт налогjunior
- Алгоритмы GC: поколенческая гипотеза, concurrent marking и write barriermiddle
- GC tradeoffs: пауза, throughput, память и давление аллокацийmiddle
- Настройка GC: пейсинг, форма кучи и наблюдаемость аллокацийmiddle
- Внутреннее устройство GC: tri-color инвариант, write barriers и глубокое погружение в рантаймыsenior
- GC в production: наблюдаемость, безопасность, edge cases и управление флотомsenior
- N+1: одна логическая операция, много round-trip''''овjunior
- Семейства фиксов: JOIN, IN, preload и DataLoadermiddle
- Обнаружение N+1: query logs, APM traces и CI gatesmiddle
- DataLoader: батчинг по дереву резолверовmiddle
- Кросс-протокольный N+1: HTTP fan-out и Redis MGETmiddle
- N+1 в масштабе: исчерпание пула, изменения планов и денормализацияsenior
- Batching: амортизируй фиксированную цену каждой операцииjunior
- Окно батчинга: размер и время ожиданияmiddle
- Batching в Kafka и Postgresmiddle
- io_uring и наблюдаемость пакетированияmiddle
- От Nagle до io_uring: эволюция пакетированияmiddle
- Backpressure, изоляция сбоев и безопасность батчей в продакшенеsenior
- Что на самом деле стоит bundle: download, parse, compile, executejunior
- Core Web Vitals: LCP, INP и CLSmiddle
- Code splitting: route-level, component-level, vendor splittingmiddle
- Tree shaking и compression: удаляем то, что не используемmiddle
- Third-party scripts: тихий убийца бюджетаmiddle
- CI enforcement и RUM: делаем бюджеты рабочимиmiddle
- V8 JIT-пайплайн, HTTP-приоритеты и безопасность bundlesenior
- Цикл performance: дисциплина, а не проектjunior
- Классификация и исправление: сопоставление family bottleneck с методамиmiddle
- Observability-стек и CI gates: ловить регрессии до выпускаmiddle
- От инцидента к enforcement: SLO burn до верифицированного исправления за 35 минутmiddle
- Культура, экономика и масштаб performancesenior
- At-most-once, at-least-once, exactly-once: три контракта доставкиjunior
- Три ножки сбоя — где реально происходят дубликаты и потериmiddle
- Consumer-side dedup: самый дешёвый путь к exactly-once processingmiddle
- Kafka exactly-once semantics: idempotent producer и транзакцииmiddle
- SQS visibility timeout, DLQ и outbox patternmiddle
- Exactly-once в production: impossibility-доказательство, гибридные паттерны и реальные инцидентыsenior
- Что такое OAuth и почему пароли — не ответjunior
- Authorization code flow с PKCEmiddle
- Валидация ID-токена и управление JWKS-кешемmiddle
- Ротация refresh-токенов и scope-based least privilegemiddle
- Sender-constrained токены: DPoP и mTLSsenior
- OAuth в production: audience атаки, observability и реальные провалыsenior