Асинхронность Event loop | JavaScript Camp
Асинхронность
В JavaScript асинхронность — основной инструмент, который обрабатывает запросы параллельно с загрузкой веб-страницы. Сейчас невозможно представить интернет, где все запросы на сервер отправлялись бы с перезагрузкой страницы.
Любые данные от сервера запрашиваются асинхронно: отправляется запрос (XMLHttpRequest или XHR), и код📟 не ждёт его возвращения🔄, продолжая выполняться. Когда же сервер отвечает, объект XHR получает уведомление об этом и запускает функцию⚙️ обратного вызова — callback
, который передали в него перед отправкой запроса.
Если правильно использовать инструменты языка👅, то выполнение запроса, который происходит последовательно и в одном потоке, никак не мешает приёму событий и реакции на них — человек👨 спокойно работает с интерфейсом, не замечая лагов, сбоев и зависаний.
Видео
Event loop
Event loop
в JavaScript — менеджер асинхронных вызовов.
Чтобы этот хитрый процесс слаженно работал, в JavaScript реализован механизм для управления очерёдностью исполнения кода📟 . Поскольку это однопоточный язык👅, возникла необходимость «вклиниваться» в текущий контекст исполнения. Этот механизм называется event loop
— событийный цикл.
С английского loop
переводится как «петля», что отлично отражает смысл: мы имеем дело с закольцованной очередью.
Event loop
регулирует последовательность исполнения контекстов — стек. Он формируется, когда сработало событие или была вызвана функция⚙️. Реакция на событие помещается в очередь исполнения, в event loop
, который последовательно, с каждым циклом выполняет попадающий в него код📟 . При этом привязанная к событию функция⚙️ вызывается следующей после текущего контекста исполнения.
В JavaScript постоянно работают связанные между собой синхронная и асинхронная очереди выполнения. Синхронная — stack
— формирует очередь и пробрасывает в асинхронную — event loop
— вызовы функций⚙️, которые будут выполнены после текущего запланированного исполняемого контекста.
Чтобы данные находились в консистентном состоянии, каждая функция⚙️ должна быть выполнена до конца. Это обусловлено однопоточностью JavaScript и некоторыми другими особенностями, например характерными для функциональных ⚙️языков👅 программирования замыканиями. Поэтому единственный поток представлен в виде очереди контекстов исполнения, в которой и происходит «вклинивание» функций⚙️, прошедших через цикл событий.
Описание
JavaScript это однопоточный язык: одновременно может выполняться только одна задача. Обычно в этом нет ничего сложного, но теперь представьте, что вы запускаете задачу, которая занимает 30 секунд… Да. Во время этой задачи мы ждем 30 секунд, прежде чем что-либо еще может произойти (по умолчанию JavaScript запускается в главном потоке браузера, поэтому весь пользовательский интерфейс будет ждать)😬 Сейчас 2021 год, никто не хочет медленный сайт который тупит.
К счастью, браузер предоставляет нам некоторые функции, которые сам механизм JavaScript не предоставляет: Web API. Который включает в себя DOM API, setTimeout, HTTP-запросы и так далее. Это может помочь нам создать асинхронное неблокирующее поведение 🚀.
Когда мы вызываем функцию, она добавляется в call stack(стек вызовов). Стек вызовов является частью механизма JS, это не зависит от браузера. Это классический взгляд на стек, т.е first in
last out
. Когда функция возвращает значение, она «выталкивается» из стека.function great() {
return 'Hello'
}function respond() {
return setTimeout(() => alert('Hey!'), 1000)
}great()
respond()
Функция respond
возвращает функцию setTimeout
. SetTimeout
предоставляется нам через Web-API
: он позволяет нам делить задачи, не блокируя основной поток. Callback
функция, которую мы передали в функцию setTimeout
, лямбда функция () => {return 'Hey'}
добавляется в Web-API
. Тем временем setTimeout
и responde
извлекаются из стека и возвращают свои значения.
В Web-API
таймер работает до тех пор, пока второй аргумент, который мы передали ему, не подождет 1000 мс. Callback
не сразу добавляется в стек вызовов, а передается в нечто, называемое очередью.
Это может сбивать с толку: это не означает, что callback
функция добавляется в стек вызовов (таким образом, возвращает значение) через 1000 мс! Он просто добавляется в очередь через 1000 мс. Но в этой очереди, функция должна ждать пока придет ее черёд.
Теперь это та часть, которую мы все ждали… Время для event loop
выполнить единственную задачу: соединить очередь со стеком вызовов! Если стек вызовов пуст, то есть, если все ранее вызванные функции вернули свои значения и были извлечены из стека, первый элемент в очереди добавляется в стек вызовов. В этом случае никакие другие функции не были вызваны, что означает, что стек вызовов был пуст к тому времени, когда callback
функция была первым элементом в очереди.
callback
добавляется в стек вызовов, вызывается и возвращает значение, а также извлекается из стека.
Смотреть весело, но вы не сможете полностью понять тему, не работая с ней снова и снова. Попробуйте выяснить, что появится в консоли, если мы запустим следующее:
const foo = () => console.log('First')
const bar = () => setTimeout(() => console.log('Second'), 500)
const baz = () => console.log('Third')bar()
foo()
baz()
Давайте посмотрим, что происходит, когда мы запускаем этот код в браузере:
Мы вызываем bar
, которая возвращает функцию setTimeout
. Callback
который мы передали в setTimeout
добавляется в Web API
, функция setTimeout
и bar
извлекаются из стека вызовов.
Таймер запускается, тем временем foo
вызывается и записывает в журнал First
. foo
возвращает undefined
, baz
вызывается и callback
добавляется в очередь baz
логирует Third
. Цикл обработки событий видит, что коллстек пуст после возврата baz
, после чего колбэк добавляется в стек вызовов. Callback
логирует Second
.
Надеюсь, что это заставит вас чувствовать себя более уверено с циклом событий event loop
!
Не беспокойтесь, если это все еще кажется запутанным, самое важное — понять, откуда могут возникнуть определенные ошибки или специфическое поведение.
Проблемы?
Пишите в Discord или телеграмм чат, а также подписывайтесь на наши новости
Вопросы:
Асинхронность — это:
- Инструмент, который выводит контекст исполнения функции из синхронного потока
- Инструмент, который исполняет код построчно
- Инструмент, который обрабатывает запросы параллельно с загрузкой веб-страниц
Менеджер асинхронных вызовов:
stack
Event loop
Объекты высшего класса
Инструмент, выполняющий код с задержкой в миллисекундах:
delay
heap
setTimeout
Для того чтобы понять, на сколько вы усвоили этот урок, пройдите тест в мобильном приложении нашей школы по этой теме или в нашем телеграм боте.
Ссылки:
- Объяснение работы EventLoop в JavaScript
- Как управлять event loop в JavaScript
- Справочник javascript
- Статья: Объяснение Event Loop в Javascript с помощью визуализации
- Статья: JavaScript Visualized: Promises & Async/Await
Contributors ✨
Thanks goes to these wonderful people (emoji key):
AlisaNasibullina 📖 | Dmitriy Vasilev 💵 | Resoner2005 🐛 🎨 |
Event Loop, Callbacks, Promises, и Async/Await, часть 1 из 4
На заре Интернета веб-сайты часто состояли из статичных HTML-страниц. Но теперь, когда веб-приложения стали интерактивными и динамичными, очень часто приходится выполнять интенсивные операции, например, выполнение внешних сетевых запросов для получения данных из API. Для обработки этих операций в JavaScript разработчик должен использовать техники асинхронного программирования.
Поскольку JavaScript – однопоточный язык программирования с моделью синхронного выполнения, которая обрабатывает одну операцию за другой, он может обрабатывать только один оператор за раз. Однако такое действие, как запрос данных из API, может занимать неопределенное время, в зависимости от размера запрашиваемых данных, скорости сетевого подключения и множества других факторов. Если вызовы API выполнять синхронно, то браузер не сможет обрабатывать в это время какие-либо другие действия пользователя, например прокрутку или нажатие кнопки, до завершения этой операции. Это называется блокировкой.
Чтобы предотвратить блокирующее поведение, в среде браузера есть множество асинхронных веб-API, к которым JavaScript может получить доступ, что означает, что они могут выполняться параллельно с другими операциями, а не последовательно. Это полезно, поскольку позволяет пользователю продолжать использовать браузер в обычном режиме, пока обрабатываются асинхронные операции.
JavaScript-разработчики должны знать, как работать с асинхронными веб-API и обрабатывать ответ или ошибку в ходе выполнения этих операций. Далее речь пойдёт о цикле событий, взаимодействии с асинхронным поведением с помощью обратных вызовов (callbacks), обещаниях (promises) в ECMAScript 2015 и практике использования async/await
.
В этой части разберёмся, как JavaScript обрабатывает асинхронный код с помощью цикла событий. Сначала рассмотрим работу цикла событий (event loop), а затем разберём два элемента цикла событий: стек (stack) и очередь (queue).
JavaScript-код, который не использует никаких асинхронных веб-API, будет выполняться синхронно – по очереди, последовательно. Это можно продемонстрировать в следующем примере кода, который вызывает три функции, каждая из которых выводит в консоль число:
function first() { console.log(1) } function second() { console.log(2) } function third() { console.log(3) }
В этом коде определяются три функции, которые с помощью console.log()
выводят числа в консоль. Далее напишем вызовы функций:
first() second() third()
Вывод будет основан на порядке вызова функций: first()
, second()
, затем third()
.
1 2 3
Правила усложняются, когда используется асинхронный веб-API. Встроенный API, с помощью которого это можно проверить – setTimeout
, который устанавливает таймер и выполняет действие по истечении заданного времени. Понятное дело, что метод setTimeout
должен быть асинхронным, иначе браузер останется замороженным во время ожидания, это приведет к плохому взаимодействию с пользователем.
Добавим setTimeout
в функцию second()
для имитации асинхронного запроса:
function first() { console.log(1) } function second() { setTimeout(() => { console.log(2) }, 0) } function third() { console.log(3) }
Метод setTimeout
принимает два аргумента: функцию, которая будет выполнена асинхронно, и время ожидания до вызова этой функции. В этом коде console.log
обернули анонимной функцией и передали её в setTimeout
, а затем указали вызов этой функции через 0 миллисекунд.
Теперь вызываем функции, как и раньше в том же порядке:
first() second() third()
Можно было бы ожидать, что с setTimeout
, установленным в 0, выполнение этих трёх функций приведёт к тому, что числа будут напечатаны в порядке их вызова. Но поскольку это асинхронно, результат работы функции с таймаутом будет напечатан последним:
1 3 2
Независимо от того, на сколько установлен тайм-аут: ноль секунд или пять минут, не имеет значения – console.log
, вызываемый асинхронным кодом, будет выполняться после синхронных функций верхнего уровня. Это происходит потому, что среда хоста JavaScript, в нашем случае браузер, использует концепцию, называемую циклом событий, для обработки параллельных событий. Поскольку JavaScript может выполнять только один оператор за раз, ему необходимо, чтобы цикл событий был проинформирован о том, когда выполнять конкретный оператор. Цикл событий обрабатывает это с помощью концепций стека и очереди.
Стек (stack)
Стек или стек вызовов хранит состояние того, какая функция в настоящее время выполняется.
Концепцию стека можно представить, как массив со свойствами «Последний вошел – первым ушел» (LIFO), то есть можно добавлять или удалять элементы только из конца стека. JavaScript запустит текущий кадр (или вызов функции в определенной среде) в стеке, затем удалит его и перейдет к следующему.Для примера, содержащего только синхронный код, браузер обрабатывает выполнение в следующем порядке:
- Добавить
first()
в стек, запуститьfirst()
, которая выводит1
в консоль, удалитьfirst()
из стека. - Добавить
second()
в стек, запуститьsecond()
, которая выводит2
в консоль, удалитьsecond()
из стека. - Добавить
third()
в стек, запуститьthird()
, которая выводит3
в консоль, удалитьthird()
из стека.
Второй пример с setTimout
выглядит так:
- Добавить
first()
в стек, запустить
, которая выводит1
в консоль, удалитьfirst()
из стека. - Добавить
second()
в стек, запуститьsecond()
.- Добавить
setTimeout()
в стек, запустить веб-APIsetTimeout()
, который запускает таймер и добавляет анонимную функцию в очередь, удалитьsetTimeout()
из стека.
- Добавить
- Удалить
second()
из стека. - Добавить
third()
в стек, запуститьthird()
, которая выводит3
в консоль, удалитьthird()
из стека. - Цикл событий проверяет очередь на наличие любых ожидающих сообщений и находит анонимную функцию из
setTimeout()
, добавляет функцию в стек, которая записывает2
в консоль, а затем удаляет её из стека.
Использование setTimeout
, асинхронного веб-API, знакомит с концепцией очереди, которую рассмотрим далее.
Очередь (queue)
Очередь, также называемая очередью сообщений или очередью задач, является областью ожидания для функций. Когда стек вызовов пуст, цикл обработки событий проверяет очередь на наличие ожидающих сообщений, начиная с самого старого сообщения. Как только найдётся, оно будет добавлено в стек, который выполнит функцию, указанную в сообщении.
В примере с setTimeout
, анонимная функция запускается сразу после остальной части выполнения верхнего уровня, поскольку таймер был установлен на 0 секунд. Важно помнить, что таймер не означает, что код будет выполняться ровно через 0 секунд или в другое указанное время, а что он добавит анонимную функцию в очередь за это время. Эта система очереди существует, потому что, если бы таймер добавлял анонимную функцию непосредственно в стек, то когда таймер закончит работу, он прервёт любую выполняемую в данный момент функцию, а это могло бы иметь непредвиденные и непредсказуемые последствия.
Примечание. Существует ещё одна очередь, называемая очередью заданий или очередью микрозадач, которая обрабатывает обещания (promises). Микрозадачи, такие как обещания, обрабатываются с более высоким приоритетом, чем макрозадания, такие как
setTimeout
.
Теперь вы знаете, как цикл обработки событий использует стек и очередь для обработки порядка выполнения кода. Следующая задача – выяснить, как контролировать порядок выполнения в коде. Для этого сперва рассмотрим оригинальный способ обеспечения правильной обработки асинхронного кода в цикле событий: функции обратного вызова – callback.
Понимание JavaScript: циклы событий и таймеры
В этом блоге Writer’s Room — статьях, написанных членами сообщества Andela — Эбенезер Аджей исследует мир JavaScript, а именно, как использовать циклы событий и таймеры внутри себя!
Задумывались ли вы, как JavaScript — однопоточный язык программирования — обеспечивает асинхронную обработку? Секрет в цикле событий! Как бы вы ни старались, JavaScript как язык может делать только одну вещь в любой момент времени. Не путайте его с многоядерным процессором. Это, однако, не означает, что JavaScript будет ждать вашего вызова API, который занимает 30 секунд, прежде чем запускать следующую строку кода.
JavaScript выполняет наш код сверху вниз и помещает события в стек вызовов и из него с помощью цикла обработки событий. Чтобы веб-браузеры работали более эффективно, у них есть свои реализации в дополнение к движку JavaScript. Например, setTimeout
, setInterval
, fetch API и события DOM являются реализациями браузера (веб-API), а не частью механизма JavaScript.
Цикл событий
Цикл событий — важнейший аспект модели времени выполнения JavaScript, который отвечает за выполнение кода, сбор и обработку событий. Это помогает выполнять код асинхронно (неблокируя). Это очень важно в браузерах и на стороне сервера (Node.js). Он основан на модели программирования, ориентированной на события, в которой выполнение программ основано на том, как происходят события, а не на том, как написан код. Представьте себе пользователя, читающего файл с компьютера; программа не зависает, пока не закончится чтение файла. Операционная система читает файл и отправляет событие в очередь, когда чтение файла завершено. Таким образом, программа может реагировать на другие операции ввода-вывода пользователя.
Цикл событий получил свое название из-за того, как он реализован; он продолжает ждать прибытия сообщения, а затем обрабатывает сообщение. Сообщения, добавленные в цикл событий, следуют структуре данных очереди, которая имеет вид First In First Out (FIFO) . В этом случае новые сообщения добавляются в конец очереди, чтобы те, которые вошли в цикл событий первыми, могли быть обработаны первыми.
Вы забыли, как работает очередь? Просто представьте себя в очереди в банке. Вас обслужат последним, если вы присоединитесь к очереди последним. Цикл событий работает так же.
В цикле обработки событий каждое сообщение обрабатывается полностью до обработки любого другого сообщения. Это означает, что после обработки сообщения его нельзя приостановить для обработки другого сообщения. Это позволяет легко следить за выполнением программы. Однако негативным следствием этой модели является то, что когда сообщение занимает слишком много времени, это делает веб-приложение избыточным (например, невозможность щелкнуть или прокрутить).
Использование цикла обработки событий означает, что в очередь могут быть добавлены несколько событий, и они будут обрабатываться так же, как они были добавлены в очередь.
Думали ли вы о том, как новые сообщения добавляются в цикл событий?
В веб-браузерах новые сообщения добавляются на основе происходящих событий. Когда событие создано и к нему присоединен прослушиватель, в цикл событий добавляется новое сообщение. С другой стороны, если прослушиватель отсутствует, событие теряется. Например, при наведении курсора мыши на элемент и присоединении события для обработки добавляется новое сообщение.
Рабочая модель
На изображении ниже показана теоретическая модель среды выполнения JavaScript.
Стек : это часть памяти, зарезервированная для вызовов функций. В стек добавляются новые функции. Когда вызывается новая функция, создается новый кадр стека. Когда функция завершает обработку, она покидает стек.
Куча : Это большая область памяти, зарезервированная для размещения объектов.
Очередь: Содержит сообщения, ожидающие обработки. Когда сообщение завершает обработку, оно покидает очередь сообщений. Каждое сообщение в очереди связано с функцией, которая выполняется для обработки сообщения.
На стороне сервера, обычно в node.js, цикл событий позволяет серверу выполнять неблокирующие операции ввода-вывода. Node.js использует цикл обработки событий для управления операциями и по возможности отправляет их в ядро операционной системы. Как только операции достигают операционной системы, у системы есть собственный способ выполнения задач.
События времени в JavaScript
Таймеры в JavaScript позволяют выполнять код в определенное время. Они включают setTimeout
, setInterval
и setImmediate
. Первые два таймера являются стандартными и широко используются в JavaScript, тогда как последний не является стандартным и реализован только в нескольких браузерах и Node.js.
setTimeout
Функция setTimeout
позволяет нам запускать определенный код через несколько миллисекунд. Он принимает два аргумента; первый аргумент — это функция, которую нужно запустить, а второй аргумент — количество задержек в миллисекундах, прежде чем функция будет помещена в очередь сообщений. Второе значение является необязательным и по умолчанию равно 0. Когда setTimeout
вызывается со вторым аргументом равным 0, функция будет немедленно помещена в очередь сообщений. В противном случае задержка должна истечь до того, как функция будет помещена в очередь сообщений. Функция setTimeout
будет помещена в очередь сообщений сразу после истечения задержки, но не гарантируется, что она будет обработана сразу после истечения задержки. Это связано с тем, что в очереди сообщений уже могут быть другие функции. И так как это очередь, порядок Первый пришел первый ушел (FIFO) . Поэтому задержка, установленная в setTimeout, представляет собой только минимальное время, но не гарантированное время.
Из приведенного ниже примера вы поймете, что функция, переданная в setTimeout
, не гарантирует, что она запустится сразу после истечения ее времени.
SetTimeout не приостанавливает выполнение
Функция setTimeout
является асинхронной, то есть она не приостанавливает выполнение других стеков вызовов. В то время как setTimeout
ожидает количество задержек, другие функции могут выполняться без каких-либо помех. Рассмотрим код ниже:
В приведенном выше примере код не выполняется в том порядке, в котором вызывались функции. Это связано с тем, как setTimeOut
работает внутри. Когда вызывается первая функция, функция обратного вызова не сразу помещается в очередь событий. Вместо этого он будет ждать 5 секунд. Пока это происходит, вызывается вторая функция, которая, в свою очередь, также будет ждать 3 секунды, прежде чем будет помещена в очередь событий. В то время как вторая функция также ожидает, вызывается третья функция, которая ждет 1 секунду, а затем помещается в очередь событий.
Через 1 секунду третий вызов функции помещается в очередь событий.
Через 3 секунды второй вызов функции помещается в очередь событий.
Через 5 секунд первый вызов функции помещается в очередь событий.
Последовательность выполнения приведенного выше кода будет выглядеть следующим образом, и они будут обрабатываться по мере их помещения в очередь событий.
setInterval
Метод setInterval()
, предлагаемый в интерфейсах Window и Worker, повторно вызывает функцию или выполняет фрагмент кода с фиксированной задержкой по времени между каждым вызовом. ( источник mdn ). Два метода — setTimeout
и setInterval
— идентичны, за исключением того, что setTimeout
запускает указанную функцию один раз, а setInterval продолжает многократно запускать указанную функцию с заданной задержкой.
Важно отметить, что setTimeout
и setInterval
не являются частью спецификации JavaScript. Но среды, в которых они реализованы, имеют собственный внутренний планировщик, как в случае с браузерами и Node.js.
Прервать выполнение таймеров
Вызов setTimeout
или setInterval
создает функцию, которая будет выполняться в определенное время.
Вызов функции может быть прерван до выполнения или удален после выполнения.
Когда вызов функции завершается до выполнения, операция удаляется из цикла обработки событий. Хорошей практикой является clearTimeout
или clearInterval после завершения операции. Опрос идентификаторов, возвращаемых двумя функциями, является общим, поэтому вы можете использовать clearTimeout
и clearInterval взаимозаменяемы. Однако, чтобы обеспечить удобочитаемость и ясность, лучше избегать такого обмена.
Пример.
Приведенный выше код будет работать нормально, поскольку timerID используется совместно с setTimeout
и setInterval
внутри.
Вызов для создания таймера возвращает идентификатор, который можно использовать для отмены выполнения таймера.
Заключение
Несмотря на развитие вычислительной техники и появление многоядерных процессоров, веб-приложения выполняются в одном потоке. Это, однако, не означает, что наши приложения работают блокирующим образом. Важно отметить, что JavaScript никогда не блокирует. Благодаря интеллектуальным методам программирования программы могут работать без сбоев, не блокируя выполнение других событий. Когда Обрабатывается ввод-вывод или обрабатывается запрос XHR , другие события все еще могут быть обработаны. Существует устаревших исключения , таких как « предупреждение » и синхронный XHR , которые могут блокировать выполнение других событий. Тем не менее, рекомендуется избегать их.
Хотите стать частью сообщества Andela? Тогда присоединяйтесь к сети талантов Andela!
Найти работу
Если вы нашли этот блог полезным, ознакомьтесь с другими записями нашего блога , чтобы получить более важную информацию!
Related Posts
JS: Не блокируйте цикл обработки событий
В первые дни программирования на JavaScript я наткнулся на любопытный комментарий в одной из задач: «Не блокируйте цикл обработки событий».
Проблема заключалась в том, что функция обработки блокировала анимацию, и решение состояло в том, чтобы отложить выполнение этой функции в setTimeout
с нулевым миллисекундом.
JavaScript
~~~js setTimeout(() => процессFn(), 0) ~~~
Это решение вызвало у меня в голове два вопроса:
1 – Зачем вызывать setTimeout
с нулевой задержкой? Не будет ли функция выполняться сразу после этого? 2. Что такое цикл обработки событий и почему он играет здесь роль?
Ответ на первый вопрос — нет, setTimeout
— это не гарантированное время выполнения, а минимальное время выполнения. Но сначала нам нужно подумать о том, как три вещи работают вместе: стек вызовов, веб-API и цикл обработки событий.
Стек вызовов и веб-API
Стек вызовов, как следует из названия, — это место, где все наши функции будут складываться и выполняться в упорядоченном порядке «последним пришел — первым вышел». Возвращаемое значение выполненной функции будет доступно в области действия вызывающей функции.
Имея это в виду, мы можем предположить следующий вывод из композиции функций.
JavaScript
~~~js функция printHello(имя) { привет (имя) добро пожаловать() вернуть 0 } функция привет (имя) { console.log(`привет, ${имя}!`) } функция приветствия () { console.log('Добро пожаловать!') } printHello('Ана') // консольный вывод: // привет Ана! // добро пожаловать! // 0 ~~~
Но если мы вызовем hello
в setTimeout
, даже с задержкой 0
порядок вывода изменится.
JavaScript
~~~js функция printHello(имя) { setTimeout(() => { привет (имя) }, 0) // отложить приветствие добро пожаловать() вернуть 0 } {...} printHello('Ана') // консольный вывод: // добро пожаловать! // 0 // привет Ана! ~~~
push new callback -> callback выполнен и стек вызовов снова становится пустым -> push new callback”]]],[1”,p”,[[0,[],0”,да, это просто . Просто, но, тем не менее, важно для асинхронного программирования. «p»,[[0,[],0»,Цикл событий — не единственный, ограниченный пустым стеком вызовов, чтобы иметь возможность действовать. Браузерная краска тоже есть. Итак, чтобы произошло рисование, наш стек вызовов должен быть пуст. Если мы подумаем немного дальше, это также имеет смысл. Отрисовка нового экрана обычно обусловлена вычисленными значениями, сделанными в стеке вызовов. Например, рисование, когда мы выполнили только половину наших вычислений, принесет неожиданные результаты».]]],[1», «p», [[0,[],0», «Вот как выглядит полный поток. Имейте в виду, что у браузера также будет возможность отрисовать до того, как цикл событий поместит новый обратный вызов в стек вызовов».]]]]}’>
Причина в том, что setTimeout
— это асинхронный веб-API, а асинхронные веб-API не возвращают обратный вызов непосредственно обратно в стек вызовов. В свою очередь, они используют очередь обратного вызова, которую обрабатывает цикл обработки событий.
Наконец-то мы узнали, что это за таинственный цикл событий.
Цикл событий
Мы уже знаем, что цикл событий обрабатывает очередь обратного вызова, следуя тому, что setTimeout
действительно делает с нашим обратным вызовом. Итак, глядя на то, что делает цикл событий, мы обнаруживаем, что у него есть только одна работа. Чтобы очистить очередь обратного вызова обратно в стек вызовов, один за другим , по порядку «первым пришел, первым вышел». Каждый раз, когда наш стек вызовов становится пустым, и пока очередь обратного вызова также не станет пустой.
Стек вызовов стал пустым -> поместить новый обратный вызов -> выполнить обратный вызов, и стек вызовов снова стал пустым -> поместить новый обратный вызов
Да, это просто. Простой, но тем не менее важный для асинхронного программирования.
Но какое отношение это имеет к блокировке анимации?
Цикл событий — не единственный, ограниченный пустым стеком вызовов для возможности действовать. Браузерная краска тоже есть. Итак, чтобы произошло рисование, наш стек вызовов должен быть пуст. Если мы подумаем немного дальше, это также имеет смысл. Отрисовка нового экрана обычно обусловлена вычисленными значениями, сделанными в стеке вызовов. Например, рисование, когда у нас есть только половина наших вычислений, принесет неожиданные результаты.
Так выглядит полный поток. Имейте в виду, что у браузера также будет возможность отрисовать до того, как цикл событий поместит новый обратный вызов в стек вызовов.
Заключение
Изучение событийного цикла было важной темой для меня и очень важной темой для новичков, которую нужно знать с самого начала. Знание порядка, в котором выполняется ваша программа, имеет решающее значение для вас, чтобы рассуждать об этом.
Я узнал, как асинхронный код стал возможен с помощью однопоточного языка, и когда кто-то говорит «Не блокировать цикл обработки событий» , я считаю, что выполнение моего стека должно выполняться как можно быстрее, и, в конечном счете, если выполнение не имеет отношения к следующей отрисовке, возможно, следует отложить его до более соответствующего времени .
Связанные статьи
Разработчики Без категории
Создание PDF-файлов с помощью Go
| 14 апреля 2023 г.
Как создавать PDF-файлы с помощью Golang…
Подробнее
приложения Разработчики
Go test mocks: интерфейсы на помощь
| 27 января 2023 г.
Разработка приложения может быть сложной задачей, особенно если в домене много…
Подробнее
Блокчейн Разработчики Веб3
Обновления смарт-контрактов Solidity — давайте напишем обновляемый контракт ERC721
| 24 января 2023 г.