Понятное объяснение цикла событий в JavaScript

В этом руководстве вы узнаете о цикле событий в 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!') и выполняет ее, что будет очень быстро.

Цикл событий javascript — стек вызовов

Обратные вызовы

Чтобы блокирующая функция не блокировала другие действия, вы обычно помещаете ее в функцию обратного вызова для последующего выполнения. Например:

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 — шаг 1

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

Цикл событий javascript — шаг 2

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

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

Цикл событий javascript — шаг 3

См. другой пример:

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, стек вызовов и цикл обработки событий.

Цикл обработки событий javascript

Рейтинг
( Пока оценок нет )
Александр Русаков / автор статьи
Программист, разработчик, 12 лет опыта работы в крупных компаниях. Быстро освоил typescript, делюсь своими знаниями на страницах этого сайта.
Загрузка ...
JavaScript и TypeScript