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

1. Очередь обратного вызова

Цикл событий работает путем непрерывного прослушивания событий и задач, добавленных в очередь обратного вызова механизмом JavaScript или другими API-интерфейсами, такими как пользовательский ввод и функции обратного вызова. Затем он передает их в том же порядке, в котором они были добавлены в стек вызовов, для выполнения по одному. Здесь важно отметить одну важную вещь: он передает задачу только в том случае, если стек вызовов пуст, что позволяет выполнять задачи в правильном порядке и не прерывает выполнение текущей задачи.

Например, взгляните на этот фрагмент кода ниже.

function funcA() {
  console.log("funcA finished");
}

// this function will take approximately 12 seconds to finish
function funcB() {
  for (let i = 0; i < 1e10; i++) {}
  console.log("funcB finished");
}

setTimeout(funcA, 500);

funcB();

clearTimeout(funcA);

// Output:
// funcB finished
// funcA finished

В этом примере выполнение `funcA` было запланировано после 500-миллисекундной задержки с использованием setTimeout, а `funcB` было выполнено сразу после этого.

Из-за длительного времени выполнения `funcB` для завершения выполнения потребовалось 12 секунд. `funcA`, который должен быть запущен через 500 миллисекунд, будет вызываться сразу после `funcB`. Заставить `funcA`ждать 12 секунд перед выводом сообщения журнала, чтобы не мешать выполнению `funcB`.

2. Очередь микрозадач

С другой стороны, очередь микрозадач — это очередь задач, выполнение которых запланировано как можно скорее. Впервые он был реализован в движке JavaScript V8, на котором работают Google Chrome и другие современные веб-браузеры, а затем представлен в стандарте HTML в 2014 году как часть спецификации HTML5.

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

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

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

Взгляните на этот код ниже, чтобы увидеть разницу между двумя очередями.

setTimeout(() => {
  console.log("this is a callback function passed to callback queue")
}, 0);

Promise
  .resolve()
  .then(() => console.log("this is a callback function passed to the microtask queue"))

clearTimeout()

// Output
// this is a callback function passed to the microtask queue
// this is a callback function passed to the callback queue

Как вы можете видеть здесь, функция обратного вызова внутри обработчика `then` напечатала свое сообщение журнала перед функцией обратного вызова внутри setTimeout, что доказывает, что очередь микрозадач имеет более высокий приоритет.

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