← Назад к вопросам
Зачем нужно не блокировать поток выполнения кода?
1.0 Junior🔥 171 комментариев
#Soft Skills и рабочие процессы
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Зачем не блокировать поток выполнения: Main Thread и UI Responsiveness
Не блокировать поток выполнения значит не заставлять браузер ждать выполнения долгих операций. В JavaScript браузера есть один главный поток (Main Thread), который отвечает за:
- Парсинг HTML и CSS
- Выполнение JavaScript
- Рендер страницы
- Обработку событий (клики, скрол)
- Реанимацию (animations, transitions)
Если Main Thread занят, браузер не может делать ничего другое. Это приводит к заморозке интерфейса.
Проблема: Блокирующий код
Плохой пример — синхронное вычисление
// Тяжелая операция, занимает 5 секунд
function heavyComputation() {
let sum = 0;
for (let i = 0; i < 1000000000; i++) {
sum += Math.sqrt(i);
}
return sum;
}
button.addEventListener('click', () => {
const result = heavyComputation(); // БЛОКИРУЕТ на 5 сек!
console.log('Готово:', result);
});
// Пока вычисляется:
// - Пользователь не может кликнуть другую кнопку
// - Анимации замирают
// - Скрол не работает
// - Интерфейс выглядит зависшим
Решение 1: Асинхронность (Async)
Используй async операции
button.addEventListener('click', async () => {
// Запроси данные с сервера (асинхронно)
const response = await fetch('/api/data');
const data = await response.json();
console.log('Данные:', data);
// Main Thread НЕ заморожен во время ожидания
});
Пока браузер ждет ответа сервера, он может:
- Обновлять UI
- Обрабатывать клики
- Рендерить анимации
Правильный паттерн: async/await
async function fetchUserData(userId) {
try {
const response = await fetch(`/api/users/${userId}`);
const user = await response.json();
updateUI(user);
} catch (error) {
showError(error);
}
}
// Не блокирует браузер свободен
fetchUserData(123);
console.log('Запрос отправлен');
Решение 2: Web Workers
Для тяжелых вычислений используй отдельный поток:
Плохо (блокирует Main Thread):
button.addEventListener('click', () => {
const result = heavyComputation();
updateUI(result);
});
Хорошо (используй Worker):
// main.js
const worker = new Worker('worker.js');
button.addEventListener('click', () => {
worker.postMessage({ task: 'compute' });
// Main Thread свободен для UI обновлений!
});
worker.onmessage = (event) => {
const result = event.data;
updateUI(result);
};
// worker.js
self.onmessage = (event) => {
const result = heavyComputation();
self.postMessage(result);
};
Решение 3: requestAnimationFrame для батча обновлений
Плохо: множество DOM обновлений
for (let i = 0; i < 1000; i++) {
// Каждое присваивание стимулирует перерисовку
element.style.left = i + 'px';
}
Хорошо: батч обновлений в одном frame
requestAnimationFrame(() => {
for (let i = 0; i < 1000; i++) {
elements[i].style.left = i + 'px';
}
// Все обновления применяются вместе
});
Решение 4: setTimeout/setInterval для распределения работы
Плохо: блокирует на долгую обработку
function processLargeArray(array) {
for (let i = 0; i < array.length; i++) {
processItem(array[i]); // Может занять 10 сек!
}
}
Хорошо: разбей на чанки
function processLargeArray(array, chunkSize = 100) {
let index = 0;
function processChunk() {
const end = Math.min(index + chunkSize, array.length);
for (let i = index; i < end; i++) {
processItem(array[i]);
}
index = end;
if (index < array.length) {
setTimeout(processChunk, 0);
}
}
processChunk();
}
Решение 5: React.useDeferredValue для отложения обновлений
function SearchResults({ query }) {
const deferredQuery = useDeferredValue(query);
return (
<>
<input value={query} onChange={/* ... */} />
<ExpensiveResults query={deferredQuery} />
</>
);
}
Ключевые метрики производительности
- FCP (First Contentful Paint) - первый контент
- LCP (Largest Contentful Paint) - самый большой контент
- TTI (Time to Interactive) - интерактивность
- FID (First Input Delay) - задержка клика
Итог
Не блокировать Main Thread - основа быстрого интерфейса. Используй:
- Асинхронность (async/await, Promises)
- Web Workers для вычислений
- requestAnimationFrame для анимаций
- setTimeout для распределения работы
- Виртуализацию для больших списков
- Правильные паттерны React
Браузер должен оставаться отзывчивым 60 кадров в секунду.