← Назад к вопросам

Зачем нужно не блокировать поток выполнения кода?

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 - основа быстрого интерфейса. Используй:

  1. Асинхронность (async/await, Promises)
  2. Web Workers для вычислений
  3. requestAnimationFrame для анимаций
  4. setTimeout для распределения работы
  5. Виртуализацию для больших списков
  6. Правильные паттерны React

Браузер должен оставаться отзывчивым 60 кадров в секунду.

Зачем нужно не блокировать поток выполнения кода? | PrepBro