W3docs

Микрозадачи в JavaScript

Очередь микрозадач в JavaScript — ключевой элемент асинхронной модели выполнения. Она гарантирует, что определённые колбэки выполнятся сразу после текущего скрипта.

В JavaScript очередь микрозадач является критически важным компонентом асинхронной модели выполнения. Она приоритизирует определённые колбэки, обеспечивая их выполнение после текущего скрипта, но до того, как цикл событий перейдёт к другим задачам — таким как рендеринг или обработка пользовательских событий. Данное руководство предлагает глубокое погружение в эффективное использование очереди микрозадач для улучшения JavaScript-приложений.

Понимание цикла событий и очереди микрозадач

Движок JavaScript использует цикл событий, управляющий выполнением скриптов и обеспечивающий неблокирующие операции. Очередь микрозадач является частью этого цикла событий. Она используется специально для промисов (см. JavaScript: Promises) и других операций, таких как queueMicrotask, гарантируя их обработку в конце текущего прогона цикла событий JavaScript, перед фазой рендеринга.

Необходимо помнить о двух различных очередях:

  • Очередь микрозадач содержит колбэки от выполненных/отклонённых промисов и от queueMicrotask(). После каждой задачи движок полностью опустошает эту очередь прежде чем делать что-либо ещё.
  • Очередь макрозадач (иногда называемая очередью задач) содержит колбэки от setTimeout, setInterval, I/O и UI-событий. За одну итерацию цикла выполняется только одна макрозадача.

Ключевое правило: когда текущий синхронный код завершается, движок сначала полностью опустошает очередь микрозадач, и только затем берёт следующую макрозадачу. Именно поэтому колбэк промиса всегда выполняется раньше колбэка setTimeout(…, 0), запланированного ранее. Полную картину взаимодействия этих очередей см. в Event Loop: Microtasks and Macrotasks.

Пример: Базовый промис


javascript— editable

В этом примере сначала в консоль выводится 'Script end', затем 'Promise resolved'. Это демонстрирует, как JavaScript откладывает выполнение промисов в очередь микрозадач.

Как работает очередь микрозадач?

Очередь микрозадач выполняет задачи, запланированные как микрозадачи. К ним относятся операции из:

  • Промисов
  • Object.observe (устаревший)
  • MutationObserver
  • API queueMicrotask()

Каждая из этих микрозадач полностью обрабатывается перед переходом к следующей или перед любым рендерингом либо выполнением других макрозадач.

Планирование микрозадач

Вы можете напрямую планировать микрозадачи с помощью функции queueMicrotask. Эта функция принимает колбэк и добавляет его в очередь микрозадач. Как видно, очередь запускается после завершения всех остальных задач.


javascript— editable

Микрозадача vs. макрозадача: почему промис опережает setTimeout(0)

Распространённый источник путаницы — почему колбэк промиса выполняется раньше колбэка setTimeout(…, 0), даже если таймер был запланирован первым. Ответ кроется в правиле выше: как только синхронный код завершается, движок полностью опустошает очередь микрозадач, прежде чем обратиться к очереди макрозадач, где живут колбэки setTimeout. Даже таймер с нулевой задержкой вынужден ждать.


javascript— editable

Вывод всегда будет таким:

1: synchronous start
2: synchronous end
3: promise (microtask)
4: setTimeout (macrotask)

Строки 1 и 2 выполняются первыми, так как синхронный код никогда не уступает управление. Затем очередь микрозадач опустошается (колбэк промиса), и только после этого следующая макрозадача — колбэк setTimeout — получает своё время. Подробнее о таймерах читайте в Scheduling: setTimeout and setInterval.

Порядок выполнения внутри очереди микрозадач

Сами микрозадачи выполняются в порядке постановки в очередь (FIFO). Смешивание колбэков .then() с queueMicrotask() наглядно это демонстрирует — оба поступают в одну очередь, поэтому результат определяется принципом «первый вошёл — первый вышел»:


javascript— editable

В консоль выводится start, end, promise 1, queueMicrotask, promise 2. Обратите внимание: микрозадача, запланированная другой микрозадачей, добавляется в ту же очередь и выполняется в том же цикле опустошения — до любого рендеринга или макрозадачи. Именно это делает бесконечные циклы микрозадач способными заблокировать остальную часть страницы.

Практическое применение микрозадач

Микрозадачи особенно полезны в сложных веб-приложениях для задач, требующих немедленного выполнения после текущего скрипта, но до того, как система обработает другие события или перерисует UI.

Сценарий: Обработка данных в реальном времени

Рассмотрим сценарий, в котором данные реального времени, поступающие с сервера, должны обрабатываться без нарушения пользовательского опыта:


javascript— editable

Этот пример демонстрирует асинхронную загрузку данных, их обработку и планирование обновления UI в очереди микрозадач.

Эффективная обработка ошибок в промисах

Эффективная обработка ошибок в асинхронном коде крайне важна. Использование очереди микрозадач совместно с обработкой ошибок промисов гарантирует, что ошибки будут обработаны сразу после логики выполнения промиса, но до других несвязанных задач.


javascript— editable

Лучшие практики использования очереди микрозадач

  1. Порядок задач: понимание того, когда применять микрозадачи для обеспечения правильной последовательности операций.
  2. Предотвращение голодания: убедитесь, что очередь микрозадач не пополняется непрерывно, не позволяя макрозадачам (например, обновлениям UI) выполняться.
  3. Отладка: трассируйте и отлаживайте выполнение микрозадач, чтобы избежать неожиданного поведения в асинхронном коде.

Заключение

Владение очередью микрозадач в JavaScript необходимо для разработки продвинутых, отзывчивых приложений. Эффективно используя этот мощный компонент модели выполнения JavaScript, разработчики могут обеспечить более плавные, неблокирующие взаимодействия и улучшенный пользовательский опыт. Это руководство предоставляет фундаментальные знания и практические навыки для эффективного использования очереди микрозадач в любом проекте на JavaScript.

Практика

Практика
Что такое микрозадача в JavaScript?
Что такое микрозадача в JavaScript?
Was this page helpful?