0 15.2K ru

Объяснение Event Loop в Javascript с помощью визуализации

Categories: 💻 Programming

Это перевод статьи Лидии Холли, где она объясняет с помощью визуализации как работает Event Loop в JS.

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

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

К счастью, браузер предоставляет нам некоторые функции, которые сам механизм JavaScript не предоставляет: Web API. Который включает в себя DOM API, setTimeout, HTTP-запросы и так далее. Это может помочь нам создать асинхронное неблокирующее поведение 🚀.

Когда мы вызываем функцию, она добавляется в call stack(стек вызовов). Стек вызовов является частью механизма JS, это не зависит от браузера. Это классический взгляд на стек, т.е  first in, last out. Когда функция возвращает значение, она "выталкивается" из стека.

call stack js

Функция response возвращает функцию setTimeout. SetTimeout предоставляется нам через веб-API: он позволяет нам делеить задачи, не блокируя основной поток. Callback функция, которую мы передали в функцию setTimeout, лямбда функция () => {return 'Hey'} добавляется в веб-API. Тем временем функция setTimeout и функция response извлекаются из стека, они оба возвращают свои значения.

timer

В Web API таймер работает до тех пор, пока второй аргумент, который мы передали ему,  не подождет 1000 мс. Callback не сразу добавляется в стек вызовов, а передается в нечто, называемое очередью.

queue

Это может сбивать с толку: это не означает, что callback функия добавляется в стек вызовов (таким образом, возвращает значение) через 1000 мс! Он просто добавляется в очередь через 1000 мс. Но в этой очереди, функция должна ждать пока придет ее черёд.

Теперь это та часть, которую мы все ждали... Время для event loop выполнить единственную задачу: соединить очередь со стеком вызовов! Если стек вызовов пуст, то есть, если все ранее вызванные функции вернули свои значения и были извлечены из стека, первый элемент в очереди добавляется в стек вызовов. В этом случае никакие другие функции не были вызваны, что означает, что стек вызовов был пуст к тому времени, когда callback функция была первым элементом в очереди.

event looks to callstack
callback добавляется в стек вызовов, вызывается и возвращает значение, а также извлекается из стека.

result

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

const foo = () => console.log("First");
const bar = () => setTimeout(() => console.log("Second"), 500);
const baz = () => console.log("Third");

bar();
foo();
baz();

Давайте посмотрим, что происходит, когда мы запускаем этот код в браузере:

browser result

  1. Мы вызываем barbar возвращает функцию setTimeout.
  2. Callback который мы передали в setTimeout добавляется в Web API, функция setTimeout и bar извлекаются из стека вызовов.
  3. Таймер запускается, тем временем foo  вызывается и записывает в журнал Firstfoo возвращает (undefined),baz вызыввается и callback добавляется в очередь
  4. baz логиркнт Third. Цикл обработки событий видит, что коллстек пуст после возврата baz, после чего колбэк добавляется в стек вызовов.
  5. Callback логирует Second.

Надеюсь, что это заставит вас чувствовать себя более уверено с циклом событий (event loop)! Не беспокойтесь, если это все еще кажется запутанным, самое важное - понять, откуда могут возникнуть определенные ошибки или специфическое поведение.

Comments:

Please log in to be able add comments.