Оптимизация Total Blocking Time (TBT) сайта под ключ
Высокий Total Blocking Time — главная причина плохого INP (Interaction to Next Paint) и, как следствие, потери конверсии. Мы видим это на каждом втором аудите: сайты с React и Next.js нередко показывают TBT свыше 500 мс, что напрямую ухудшает пользовательский опыт. Наша команда с 5+ лет опыта в оптимизации Core Web Vitals знает, как снизить TBT до зелёной зоны — менее 200 мс на десктопе и 300 мс на мобильном устройстве с троттлингом CPU 4×.
TBT складывается из длинных задач (Long Tasks), каждая из которых длится более 50 мс. Если выполнить три задачи по 80 мс, блокировка составит 90 мс. Каждая такая миллисекунда откладывает отрисовку следующего кадра, увеличивая время до полной интерактивности. Снижение TBT на 100 мс может улучшить INP на 30–50%, что подтверждают полевые замеры.
Мы предлагаем комплексную оптимизацию TBT под ключ: от диагностики до внедрения мониторинга. Закажите аудит — и мы подготовим план со сроками и оценкой эффекта без оплаты.
Как диагностировать причины высокого TBT?
Первый шаг — найти Long Tasks. Chrome DevTools, вкладка Performance: записываем загрузку страницы, смотрим красные полосы над main thread. Программно используем Long Task API:
const observer = new PerformanceObserver((list) => { for (const entry of list.getEntries()) { console.log({ name: entry.name, duration: entry.duration, startTime: entry.startTime, attribution: entry.attribution, }); } }); observer.observe({ type: 'longtask', buffered: true }); // Данные можно отправлять в аналитику через fetch с keepalive attribution покажет, в каком фрейме или скрипте возникла задача. Это первый шаг к точечной оптимизации.
Причина №1: тяжёлый JavaScript при старте
Самая частая причина высокого TBT — большой JS-бандл, который парсируется и выполняется синхронно при загрузке. Каждый мегабайт JS требует ~1 секунды парсинга на среднем мобильном устройстве. Решение — code splitting + lazy loading:
const HeavyChart = lazy(() => import('./HeavyChart')); const DataTable = lazy(() => import('./DataTable')); function Dashboard() { const [showChart, setShowChart] = useState(false); return ( <div> <button onClick={() => setShowChart(true)}>Показать график</button> {showChart && ( <Suspense fallback={<Skeleton />}> <HeavyChart /> </Suspense> )} </div> ); } Для роутов — React.lazy + react-router. Code splitting снижает TBT в 2–3 раза, так как initial chunk становится меньше 150 kB gzip.
Причина №2: синхронные сторонние скрипты
Google Tag Manager, чаты, пиксели рекламных сетей — каждый сторонний скрипт может создавать Long Tasks. Диагностика в Chrome DevTools: Performance → Bottom-up → группировка по домену. Решения:
<!-- Используем async или defer: --> <script src="https://widget.example.com/chat.js" async></script> <!-- Или отложенная загрузка после взаимодействия: --> <script> function loadChat() { const s = document.createElement('script'); s.src = 'https://widget.example.com/chat.js'; document.head.appendChild(s); } ['click', 'scroll', 'keydown'].forEach(event => { window.addEventListener(event, loadChat, { once: true }); }); </script> Для GTM: отложенный запуск триггера «DOM Ready» вместо «Page View» для некритичных тегов.
Причина №3: тяжёлые вычисления в main thread
Сортировка больших массивов, сложные DOM-манипуляции — всё это блокирует main thread. Web Worker выгружает вычисления в отдельный поток:
// worker.js self.onmessage = function(e) { const { data, operation } = e.data; let result; switch (operation) { case 'sort': result = heavySort(data); break; case 'filter': result = complexFilter(data); break; } self.postMessage(result); }; // main.js const worker = new Worker('/worker.js'); worker.postMessage({ data: largeArray, operation: 'sort' }); worker.onmessage = (e) => setTableData(e.data); Для разбивки длинных синхронных циклов используйте scheduler.yield() (Chrome 94+) или полифил через setTimeout.
Причина №4: тяжёлый hydration в SSR/SSG
Next.js, Nuxt, Gatsby — при hydration фреймворк повторно обходит весь DOM. Решения: Partial hydration (Islands architecture), Progressive hydration, React 18 startTransition:
import { startTransition } from 'react'; function SearchResults() { const [results, setResults] = useState([]); function handleSearch(newQuery) { startTransition(() => setResults(fetchResults(newQuery))); } } Измерение TBT в полевых условиях
TBT нельзя измерить в браузере напрямую, но INP — его production-аналог. Используем web-vitals:
npm install web-vitals import { onINP } from 'web-vitals'; function sendToAnalytics(metric) { navigator.sendBeacon('/api/vitals', JSON.stringify({ name: metric.name, value: metric.value, rating: metric.rating, id: metric.id, url: location.href })); } onINP(sendToAnalytics); Настраиваем алерты при выходе INP за пределы зелёной зоны.
Сравнение методов оптимизации TBT
| Метод | Эффективность | Время внедрения | Сложность |
|---|---|---|---|
| Code splitting | Снижает TBT в 2-3 раза | 1–2 дня | Средняя |
| Web Worker | Разгружает main thread до 50% | 1 день | Низкая |
| Отложенная загрузка скриптов | Убирает 100-500 мс | Полдня | Низкая |
| Оптимизация hydration | Снижает TBT до 40% | 3–5 дней | Высокая |
Контрольный чеклист оптимизации TBT
- Разбили JS-бандл: initial chunk < 150 kB gzip, роуты ленивые
- Сторонние скрипты: все некритичные — с
deferили отложенной загрузкой - Тяжёлые вычисления вынесены в Web Worker
- Длинные синхронные циклы разбиты через
scheduler.yield() - React:
startTransitionдля некритичных обновлений,useDeferredValueдля фильтрации - Проверили рекламные сети: AdSense, Yandex Ads часто дают 200–500 мс TBT
Что входит в работу
- Диагностика TBT и Long Tasks с отчётом по источникам блокировки
- План оптимизации с конкретными шагами и оценкой эффекта
- Внедрение code splitting, lazy loading, Web Workers
- Оптимизация сторонних скриптов и hydration
- Настройка полевого мониторинга INP с алертами
- Передача документации и доступов к инструментам
- Бесплатная консультация и поддержка 2 недели после сдачи
Сроки и стоимость
Диагностика и составление плана — 1–2 рабочих дня. Code splitting + ленивая загрузка типового React-приложения — 3–5 рабочих дней. Полный цикл: диагностика, оптимизация, настройка мониторинга INP в продакшне — 1,5–3 недели в зависимости от сложности приложения. Стоимость рассчитывается индивидуально после аудита.
Свяжитесь с нами — мы оценим ваш проект и подготовим план оптимизации TBT с гарантией результата.







