Javascript - это однопоточный язык во время выполнения, что означает, что одновременно может происходить только одно событие. То есть движок JavaScript может обрабатывать только один оператор за раз в одном потоке. Это также означает, что вы не можете выполнять длительные операции, такие как доступ к сети, без блокировки основного потока. Вот где в игру вступает асинхронный JavaScript. Используя асинхронный JavaScript (например, обратные вызовы, обещания и async / await), вы можете выполнять длинные сетевые запросы, не блокируя основной поток.

Когда вы открываете веб-сайт в браузере, он использует один поток выполнения JavaScript. Этот поток отвечает за все, например за прокрутку веб-страницы, печать чего-либо на веб-странице, прослушивание событий DOM (например, когда пользователь нажимает кнопку) и выполнение других действий.

Как JavaScript может быть однопоточным и неблокирующим одновременно? Как насчет того, чтобы запускать таймеры? Петли?

Как работает асинхронный JavaScript?

Чтобы понять, как выполняется этот код, мы должны понимать цикл событий.

ПЕТЛЯ СОБЫТИЙ

Терминология, используемая в цикле событий JavaScript:

HEAP - это место (память), где хранятся объекты, когда мы определяем переменные.

СТЕК, который представляет собой обычный стек вызовов, содержащий все вызываемые функции. Когда мы вызываем функцию для ее выполнения, мы помещаем ее в стек. По завершении выполнения он выталкивается из стека.

WEB API отвечают за заполнение очереди обратного вызова, предоставляя множество функций, таких как возможность делать запрос AJAX, setTimeout, события DOM. Когда мы используем эти API, мы используем таблица событий. Таблица событий отслеживает обратные вызовы для соответствующих событий. Как только происходит событие, т. Е. Завершается асинхронная операция, обратный вызов этого события помещается в очередь обратного вызова.

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

ЦИКЛ СОБЫТИЙ - это процесс, который проверяет, пуст ли стек вызовов и содержит ли очередь обратного вызова отложенную задачу для обработки, если это так, - вызывает обработчик событий верхнего уровня и удаляет его из очереди. .

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

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

Выполнение setTimeout

См. Рис. 2.1- В первой строке двигатель встречает приветствие (). Он добавляется в стек вызовов, после чего записывает значение. Метод извлекается из стека вызовов. Движок встречает метод setTimeout, который помещается в стек вызовов.

Обратитесь к рис. 2.2. Функция обратного вызова setTimeout будет добавлена ​​в веб-API, пока не будет установлен таймер (1 секунда).

См. Рис. 2.3 - Обратный вызов по таймауту добавляется в очередь обратного вызова (очередь макрозадач) через 1 секунду.

См. Рис. 2.4 - Движок видит, что стек вызовов теперь пуст. Обратный вызов setTimeout помещается в стек вызовов.

См. Рис. 2.5 - Строка возврата функции обратного вызова. Возврат обратного вызова setTimeout появляется.

НУЛЕВЫЕ ЗАДЕРЖКИ на самом деле не означает, что обратный вызов сработает через ноль миллисекунд. Вызов setTimeout с задержкой в ​​0 (ноль) миллисекунд не выполняет функцию обратного вызова по истечении заданного интервала.

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

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

Исполнение обещаний

В каком порядке должны появляться журналы?

начало скрипта
конец скрипта
обещание1
обещание2
setTimeout

Почему обещание1 и обещание2 получают печать до setTimeout?

Очередь заданий ES6 / очередь микро-задач

ES6 представил концепцию очереди заданий / очереди микро-задач, которая используется Promises в JavaScript. M acrotask или просто вызываемая очередь задач - это код, который необходимо выполнить после того, как стек выполнения будет пуст. Макрозадачи носят неблокирующий характер. setInterval, setImmediate, setTimeout, I / O tasks, DOM Manipulation используют очередь макрозадач для выполнения своих обратных вызовов . Promises, MutationObservers, IntersectionObservers и т. д. используют очередь микрозадач для запуска их обратных вызовов. Разница между очередью сообщений и очередью микрозадач состоит в том, что очередь микрозадач имеет более высокий приоритет, чем очередь сообщений, что означает, что задания обещаний внутри очереди заданий / очереди микрозадач будут выполняться перед обратными вызовами внутри очереди сообщений.

синхронизировать задачи → микро-задачи → макро-задачи

  1. Все функции, которые в настоящее время находятся в стеке вызовов, выполняются. Когда они вернули значение, они выскочили из стека.
  2. Когда стек вызовов пуст, все стоящие в очереди микрозадачи помещаются в. вызовите стек один за другим и приступайте к выполнению! (Сами микрозадачи также могут возвращать новые микрозадачи, фактически создавая бесконечный цикл микрозадач.) Микрозадачи также выполняются в конце каждой макрозадачи.
  3. Если и стек вызовов, и очередь микрозадач пусты, цикл обработки событий проверяет, остались ли задачи в очереди задач (макросов). Задачи помещаются в стек вызовов, выполняются и отключаются!

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

Объяснение примера

См. Рис. 4.1. В первой строке движок обнаруживает метод консоли. Он добавляется в стек вызовов, после чего регистрирует начало значения! к консоли. Метод извлекается из стека вызовов, и движок продолжает работу.

См. Рис. 4.2. Движок обнаруживает setTimeout, который появляется в стеке вызовов. Его функция обратного вызова будет добавлена ​​в веб-API, пока таймер не сработает. Хотя мы предоставили таймеру значение 0, обратный вызов по-прежнему сначала передается в веб-API, а затем добавляется в очередь макрозадач.

См. Рис. 4.3. Движок обнаруживает метод обещания. Метод обещания добавляется в стек вызовов, а затем его функция обратного вызова добавляется в веб-API. при разрешении обещания его функция обратного вызова добавляется в очередь микрозадач.

См. Рис. 4.4. Движок обнаруживает метод консоли. Он немедленно добавляется в стек вызовов, после чего регистрирует значение End! на консоль, извлекается из стека вызовов, и движок продолжает работу.

См. Рис. 4.5. Движок видит, что стек вызовов теперь пуст. он проверит, есть ли задачи в очереди микрозадач! И да, это обещание, тогда обратный вызов ждет своей очереди! Он попадает в стек вызовов, после чего регистрирует разрешенное значение обещания.

См. Рис. 4.6. Механизм видит, что стек вызовов пуст, поэтому он собирается еще раз проверить очередь микрозадач, чтобы увидеть, поставлены ли задачи в очередь. Нет, очередь микрозадач пуста. Обратный вызов setTimeout передается в стек вызовов. Функция обратного вызова возвращает метод консоли. Обратный вызов setTimeout извлекается из стека вызовов.

Заключение

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

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