Я начал изучать Javascript около 2 лет назад, и мне было интересно найти кусочки и кусочки, чтобы изучить, как он работает внутри. Я должен был услышать такие слова, как механизм выполнения v8, который работает в браузере, но ничего не знал об этом и начал проводить собственные исследования и эксперименты в браузере. В основном все разработчики JS, возможно, слышали термин V8, среда выполнения Chrome, но некоторые, возможно, даже не знали, что это значит и что это делает.

Прежде всего, что такое Javascript под капотом — основной компонент NodeJS. Что ж, JS — это однопоточный, однопараллельный язык со стеком вызовов, циклом событий, очередью обратного вызова и некоторыми другими API. Если мы говорим о среде выполнения v8 в браузере, ниже приведено упрощенное представление о том, что это такое на самом деле…

Что такое стек вызовов?

Вы можете думать, что стек вызовов является функциональным стеком или стеком выполнения, когда ваш код Javascript выполняется построчно. Если часть кода не передана в очередь обратного вызова, она заполняет стек вызовов механизма выполнения.

Рассмотрим следующее изображение для понимания.

Здесь, во-первых, JS предназначен для запуска в потоке main(), поэтому функция main() будет вызываться первой, когда мы все вместе выполняем приведенный выше код. Входной точкой выполнения является оператор console.log(), и выполнение будет остановлено до тех пор, пока аргумент, предоставленный внутри, не завершит свое выполнение, то есть bar(6). Теперь полоса (6) будет помещена в стек, а затем вызовет функцию foo (3 * 6) и, следовательно, окажется наверху. Теперь, когда выполнение foo() завершится, он вернет результат, извлекая запись из стека и переходя к bar(6), который, в свою очередь, вернет запись в консоль и распечатает результат.

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

function add(a, b) {
  throw Error("something went wrong");
}function bar(a,b) {
  add(3,4)
  return a-b
}bar(3,4)

Иногда мы попадаем в бесконечный цикл из-за ограничения размера стека, которое составляет 16 000 кадров для браузера Chrome, что может произойти из-за повторяющихся вызовов функций, и браузер пытается убить вас и выдает «RangeError: максимальный размер стека превышен».

Веб-API

Есть несколько модулей JS, таких как XMLHttpRequest, Timeout и события DOM, которые попадают в Web API. Веб-API начинает выполнение, а когда выполнение завершается, он помещает вызов функции в очередь задач, которую мы обсудим позже в следующем разделе. WebAPI не могут сами поместить код выполнения в стек, и здесь на сцену выходит очередь задач.

когда приведенные ниже фрагменты кода выполняются, они немедленно передаются веб-API и выполняют свою работу.

//timeout or execution after some delay
setTimeout(function() {
   console.log('after delay')
}, 5000);//XMLHttpRequest call
fetch('https://example.api.com').then(function(result) {
    console.log(result);
});//DOM event
document.getElementById('btn-submit').onclick = function(event) {
    clicked++;
    console.log(event.target.value);
}

См. изображение выше для иллюстрации. когда он помещает setTimeout в стек, он отправляется в работающий модуль webapis и выполняется в фоновом режиме, пока не завершит выполнение.

Цикл событий

Основной обязанностью цикла обработки событий является мониторинг очереди задач и состояния стека. Если должны быть выполнены некоторые функции обратного вызова, которые присутствуют в очереди задач из webapis, они подхватываются циклом событий и помещаются в стек, если он пуст. Если стек находится в состоянии выполнения или простыми словами, если он не пуст, то обратные вызовы в очереди задач должны ждать, пока стек вызовов не станет пустым. Таким образом, не гарантируется, что функция setTimeout() будет выполняться с указанной задержкой, и, возможно, ей придется ждать в очереди задач, если функции стека вызовов занимают больше времени для выполнения.

Интересно, что приведенный ниже код выполняется не асинхронно, а синхронно.

let arr = [2,3,7,8,9,11,3,4]arr.filter(i => i%2 == 0)
 .forEach(function(i) {
 console.log(i);
})

Теперь, основываясь на приведенном выше объяснении, очевидно, что функция setTimeout(), определенная с задержкой 0 мс, не гарантирует немедленного выполнения, поскольку она сначала помещается в стек, а затем запускается таймер, запускаемый webapi и ожидающий в очереди задач. до того, как он будет выбран циклом событий для повторного помещения в стек вызовов.

Для приведенного выше кода вывод отображается, как показано выше, а оператор, написанный внутри setTimeout(), выполняется в конце и печатает сообщение.

В заключение, все компоненты, описанные выше, работают вместе, чтобы обеспечить выполнение кода JS в однопоточном режиме.

Удачного кодирования !!