В этом руководстве вы узнаете о цикле событий в JavaScript и о том, как JavaScript реализует модель параллелизма на его основе. Рассмотрим понятное объяснение цикла событий в JavaScript.
Однопоточная модель
JavaScript — это однопоточный язык программирования. Это означает, что JavaScript может выполнять только одну операцию в один и тот же момент времени.
Движок JavaScript выполняет скрипт из верхней части файла и работает вниз. Он создает контексты выполнения, помещает и извлекает функции из стека вызовов на этапе выполнения.
Если функция выполняется долго, вы не можете взаимодействовать с веб-браузером во время выполнения функции, потому что страница зависает.
Функция, выполнение которой занимает много времени, называется блокирующей функцией. Технически функция блокировки блокирует все действия на веб-странице, например щелчок мышью.
Примером блокирующей функции является функция, которая вызывает API с удаленного сервера.
В следующем примере используется большой цикл для имитации блокирующей функции:
function task(message) {
// emulate time consuming task
let n = 10000000000;
while (n > 0){
n--;
}
console.log(message);
}
console.log('Start script...');
task('Call an API');
console.log('Done!');В этом примере у нас есть большой цикл while внутри функции task(), который эмулирует трудоемкую задачу. Функция task() является блокирующей.
Скрипт зависает на несколько секунд(в зависимости от скорости компьютера) и выдает следующий вывод:
Start script... Download a file. Done!
Чтобы выполнить сценарий, механизм JavaScript помещает первый вызов console.log() поверх стека вызовов и выполняет его. Затем он помещает функцию task() поверх стека вызовов и выполняет функцию.
Однако для завершения функции task() потребуется некоторое время. Поэтому вы увидите сообщение 'Download a file.' немного времени спустя. После завершения функции task() движок JavaScript извлекает ее из стека вызовов.
Наконец, движок JavaScript делает последний вызов функции console.log('Done!') и выполняет ее, что будет очень быстро.

Обратные вызовы
Чтобы блокирующая функция не блокировала другие действия, вы обычно помещаете ее в функцию обратного вызова для последующего выполнения. Например:
console.log('Start script...');
setTimeout(() => {
task('Download a file.');
}, 1000);
console.log('Done!');В этом примере вы увидите сообщение 'Start script...' и 'Done!' немедленно. И после этого вы увидите сообщение 'Download a file'.
Вот результат:
Start script... Done! Download a file.
Как упоминалось ранее, движок JavaScript может делать только одну вещь за раз. Однако точнее будет сказать, что среда выполнения JavaScript может выполнять одну операцию за раз.
Веб-браузер также имеет другие компоненты, а не только механизм JavaScript.
Когда вы вызываете функцию setTimeout(), отправляете запрос на выборку или нажимаете кнопку, веб-браузер может выполнять эти действия одновременно и асинхронно.
setTimeout(), запросы на выборку и события DOM являются частью веб-API веб-браузера.
В нашем примере при вызове функции setTimeout() движок JavaScript помещает ее в стек вызовов, а веб-API создает таймер, который истекает через 1 секунду.

Затем движок JavaScript помещает функцию task() в очередь, называемую очередью обратного вызова или очередью задач:

Цикл событий — это постоянно работающий процесс, который отслеживает как очередь обратного вызова, так и стек вызовов.
Если стек вызовов не пуст, цикл событий ожидает, пока он не станет пустым, и помещает следующую функцию из очереди обратного вызова в стек вызовов. Если очередь обратного вызова пуста, ничего не произойдет:

См. другой пример:
console.log('Hi!');
setTimeout(() => {
console.log('Execute immediately.');
}, 0);
console.log('Bye!');В этом примере время ожидания равно 0 секундам, поэтому появляется сообщение 'Execute immediately.' должно появиться перед сообщением 'Bye!'. Однако это так не работает.
Движок JavaScript помещает следующий вызов функции в очередь обратного вызова и выполняет его, когда стек вызовов пуст. Другими словами, движок JavaScript выполняет его после console.log('Bye!').
console.log('Execute immediately.');Вот результат:
Hi! Bye! Execute immediately.
На следующем рисунке показана среда выполнения JavaScript, веб-API, стек вызовов и цикл обработки событий.

