Что такое V8 и как работают асинхронные вычисления.

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

Мне стало любопытно, и я углубился в то, как асинхронные задачи работают в Javascript. После тонны исследований я хотел собрать все, что я узнал, в простую и понятную статью.

Двигатель V8

Javascript работает на движке с открытым исходным кодом под названием V8, который отвечает за анализ вашего кода в токены и преобразование его в исполняемые команды системы. Его среда выполнения имеет стек вызовов и кучу. Куча — это место, где выделяется динамическая память, и, возможно, это тема для обсуждения позже, поскольку она не связана с нашей текущей темой. Давайте подробно разберемся со стеком вызовов, взяв пример фрагмента кода.

function foo1() {
  console.log('Hi')
}
function foo() {
  foo1()
}
foo()

Любой файл javascript будет заключен в анонимную функцию с именем «main()», которая будет сначала подключена к стеку вызовов.

Функция main вызывает функцию «foo()», которая затем монтируется в стек.

Эта функция монтирует функцию «foo1()» внутри себя в стек, которая помещает «console.log(«Hi»)» в стек вызовов. Функция «console.log()» записывает строку «Привет» в консоль и выталкивается.

Функция "foo1()" завершает выполнение всех инструкций внутри себя и извлекается из стека. Точно так же оставшиеся две функции также извлекаются. Это очищает стек, и программа завершена.

Среда выполнения Chromium и setTimeout

Но V8 является однопоточным приложением и не реализует никаких асинхронных функций или популярных асинхронных функций, таких как setTimeout, setInterval или XMLHttpRequest. Эти функции реализованы в виде веб-API и обрабатываются браузерами или локальными поставщиками среды выполнения, такими как nodeJS. А пока давайте посмотрим, как приведенный выше фрагмент кода будет выглядеть в среде выполнения Javascript в Google Chrome (почти все браузеры обрабатывают это одинаково).

Chrome оборачивает движок V8 и реализует цикл обработки событий, очередь задач и некоторые веб-API, которые выполняются в другом потоке. Веб-API включают объект документа (DOM), запросы ajax и такие функции, как setTimeout и setInterval. Чтобы понять, как это работает, давайте возьмем пример кода с асинхронной функцией, такой как setTimeout.

console.log("Hi")

setTimeout(function callback() {
  console.log("timeout")
},5000)

console.log("completed")

Сначала в стек вызовов V8 монтируется функция «main()», за которой следует console.log(«Hi»)», которая регистрирует «Hi» в стеке вызовов V8. консоль, и появляется.

Теперь setTimeout монтируется в стек вызовов. Вместо ожидания завершения работы таймера в течение 5 секунд функция обратного вызова "callback()" передается в поток веб-API, который обрабатывает таймер.

Не дожидаясь ответа, он извлекается из стека, а следующий console.log("completed")" помещается в стек.

Как только console.log() записывает строку «completed» на консоль, она извлекается вместе с функцией «main()», очищающей стек.

Как только таймер в потоке веб-API завершен, функция не помещается непосредственно в стек вызовов, что может помешать выполнению текущих инструкций, а помещается в очередь задач.

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

В нашем случае он отправил функцию «обратного вызова», которая отправила «console.log(«timeout»)», и «timeout» записался в консоль.

Оставшиеся два элемента, наконец, извлекаются, очищая стек вызовов и завершая программу.

И вот, теперь мы знаем, как работает среда выполнения javascript и как она обрабатывает асинхронные вычисления. Там может быть несколько ошибок, поэтому не стесняйтесь пинговать меня в комментариях, если вы их найдете.

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