Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Що таке довгі задачі в головному потоці і як розбити важке обчислення, щоб інтерфейс не зависав?

Поки JavaScript виконується, браузер не може обробити клік, натискання клавіші чи перемалювати сторінку. Довга задача (long task) - це шматок роботи головного потоку понад 50 мс. Користувач бачить «завислий» інтерфейс, а метрика INP (Interaction to Next Paint) погіршується.

// обробка 50 000 рядків одним циклом - інтерфейс завмирає на секунду
rows.forEach((row) => renderRow(row));

Async-функція сама по собі не допомагає. await всередині циклу над синхронною роботою не віддає керування браузеру надовго: мікрозадачі виконуються одна за одною до порожньої черги, і браузер між ними не малює.

Рішення 1 - віддавати керування між шматками:

async function processInChunks(items, handle) {
  let deadline = performance.now() + 40;
  for (const item of items) {
    handle(item);
    if (performance.now() > deadline) {
      await yieldToMain();
      deadline = performance.now() + 40;
    }
  }
}

function yieldToMain() {
  if (globalThis.scheduler?.yield) {
    return scheduler.yield();              // продовження отримує пріоритет
  }
  return new Promise((resolve) => setTimeout(resolve, 0));
}

scheduler.yield() віддає керування браузеру, але ставить продовження попереду інших задач, тож робота не «загубиться» в черзі. Він підтримується не всюди, тому потрібен запасний варіант через setTimeout.

Рішення 2 - винести обчислення з головного потоку у Web Worker. Підходить для чистих обчислень (парсинг великого файлу, стиснення, криптографія), але воркер не має доступу до DOM.

Рішення 3 - не робити зайвої роботи:

  • віртуалізація довгих списків - рендерити лише видимі 30 рядків замість 50 000;
  • requestIdleCallback для некритичної роботи (аналітика, попереднє завантаження) - коли браузеру нічим зайнятися;
  • debounce для обробників, що спрацьовують на кожне натискання клавіші.

Як знайти довгі задачі: вкладка Performance у DevTools (позначені червоним), або програмно:

new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) console.warn('Long task', entry.duration);
}).observe({ type: 'longtask', buffered: true });

Докладніше в документації: Scheduler.yield()

Перевір себе

20 випадкових питань за спробу, після завершення - розбір кожної помилки

Схожі питання