Механизм работы JS, понятный каждому

браузер

предисловие

Эта статья основана на рабочем механизме JS, разделенном собственным пониманием идей автора.Мнения ограничены, а упущения неизбежны.Добро пожаловать, чтобы оставить сообщение для исправлений и обменов.

браузер

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

Основные функции браузера можно описать так:

  • Показать ресурсы
  • функциональное взаимодействие

ядро браузера

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

  • движок рендеринга
  • Javascript-движок

движок рендеринга

Механизм рендеринга: конвертируйте HTML, CSS, текст Javascript и соответствующие ресурсы в результаты изображения.
Его основная функция — анализировать файлы ресурсов и отображать их на экране.
В то же время это также то, что мы обычно называем узким смыслом.浏览器内核

подумайте об этом, упомяните浏览器内核Что мы сразу думаем?

  • Webkit (сафари, старые версии хрома)
  • Trident (старый друг IE)
  • Геккон (Знакомый незнакомец Firefox)
  • Блинк (новая версия хрома)

Основное содержание их работы — отрисовка соответствующей структуры страницы и формы представления в соответствии с определениями нашего HTML, CSS и JS.

Javascript-движок

1. Что это? Почему? делать что?

Javascript это解释型语言, компиляция не будет выполняться до запуска кода, а исходный код будет преобразован в промежуточный код, такой как байт-код или машинный код,
Вместо этого он компилируется в режиме реального времени в процессе выполнения и выполняется во время компиляции.

Следовательно, для выполнения работы, связанной с компиляцией и преобразованием, необходим функциональный модуль.Javascript引擎Просто делать эти вещи.
В итоге:Разбирать исходный код JS во время выполнения, преобразовывать его в исполняемый машинный код и выполнять..

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

2. Распространенные движки Javascript

Общие механизмы Javascript следующие:

  • Движок Chrome V8 (хром, Node, Opera)
  • ПаукОбезьяна (Firefox)
  • Нитро (Сафари)
  • Чакра (край)

НО, полагаться только наJavascript引擎На самом деле он не подходит для работы браузера с JS-обработкойJavascript引擎Просто небольшой строительный блок в модулях браузера, связанных с JS.

Время выполнения

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

Переполнение стека высоко оцененоотвечать, о механизме Javascript и среде выполнения Javascript.

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

  • Разобрать код JS и преобразовать его в исполняемый машинный язык
  • Предоставьте некоторые дополнительные объекты (API), которые могут взаимодействовать с кодом JS.

Первая часть работы состоитJavascript引擎
Выполнение второй части функции на самом деле то, о чем мы говорили в этом разделе.Javascript Runtime, так что мы можем примерно понять, что,Javascript Runtime — это область, созданная хост-средой JS.В этой области JS может получить доступ к ряду функций, предоставляемых хост-средой.

Каковы распространенные среды хостинга JS?

  • веб-браузер
  • node.js

node

Затем в этих двух средах соответствующие механизмы и среды выполнения следующие:

хост-среда JS-движок функции времени выполнения
браузер хромированный двигатель V8 DOM, оконные объекты, пользовательские события, таймеры и т. д.
node.js хромированный двигатель V8 требуют объекты, буферы, процессы, fs и т. д.

Один и тот же JS-движок предоставляет разные возможности в разных средах.

Короче говоря, оригинальный js был разработан только для проверки веб-страниц, но в разных средах.Javascript RuntimeJS может сделать больше работы.

Пока у нас есть простое представление о среде выполнения JS.

Далее рассмотрим механизм работы JS исходя из логики выполнения кода в среде браузера.

JS-движок

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

  • куча памятиФактическое значение ссылочного типа, где выделена память
  • стек вызововХранилище базового типа, хранилище имени адреса ссылочного типа, где выполняется логика кода

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

JS引擎

куча памяти

Где хранить данные типа ссылки на элемент, выделенную системой память,
Данные ссылочного типа в JS,реальная стоимостьОн разбросан здесь
Фактически хранилище ссылочных типов разделено на две части:

  • Реальное значение хранится в памяти, которая является системой по своему положению.Там, где есть подходящее место в области памяти, оно размещается там, где оно есть.Строгого порядка нет, поэтому говорят, что оно разбросано .
  • Адрес физической памяти, где находится реальное значение. Это значение хранится в стеке в виде базового значения.

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

стек выполнения

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

Движок разделит код на частиисполняемый модуль, а затем по очереди входят в стек исполнения и выполняются

Так что же такое исполняемый модуль?

Исполняемый модуль, стандартный язык执行上下文
JS,执行上下文Это может быть следующее:

  • Глобальный код -----> Глобальный контекст выполнения
  • Код функции -----> контекст выполнения функции
  • Eval-код -----> контекст выполнения функции eval

Что общего у этих вещей?

Глобальный код можно рассматривать как IIFE (немедленное выполнениефункция),
функция в целомфункция
eval может выполнить входящую строкуфункция

Функция, это все функции

Следовательно, мы можем примерно понять это как: вещи в стеке выполнения все одна за другой函数调用.

  • Во-первых, весь JS-код входного файла вызывается как IIFE, который сначала помещается в стек.
  • Затем в процессе фактического выполнения, когда вызываются другие функции, они будут помещены в стек для последовательного выполнения.

Поэтому принципиальную схему движка JS можно обновить следующим образом:

один поток

JS однопоточный. хорошо известны всем людям.

В чем смысл?
В движке JS выполнение кода происходит в стеке вызовов.
Стек — это структура данных LIFO (последний пришел — первый вышел).
Будет обработана только функция на вершине стека.После завершения обработки стек будет извлечен, и следующие функции войдут в вершину стека, а затем будут выполнены...

Например 🌰:

Следующий JS-файл

function first() {
  second();  
}

function second() {  
  console.log('log fn');  
}

first();

... // 后续操作

入栈示意图

Шаги для JS-движка для обработки этого кода следующие (сосредоточьтесь только на вызовах функций)

  1. Весь код помещается в стек как IIFE, а вызов функции main() попадает в верхнюю часть стека и начинает выполнение.
  2. При встрече с первым вызовом функции первая функция попадает в вершину стека и начинает поступать в тело первой функции для выполнения (в это время основная функция еще не выполнена)
  3. После входа в тело первой функции, когда вызывается вторая функция, поместите вторую функцию на вершину стека и введите тело второй функции для выполнения.
  4. После входа во второе тело функции встретите вызов функции console.log, поместите console.log в верхнюю часть стека.
  5. После того, как функция console.log напечатана, выполнение завершается, и вершина стека выталкивается.
  6. В это время вершиной стека является вторая функция, продолжайте выполнять код после console.log в теле второй функции и обнаружите, что исполняемый код отсутствует, ОК, затем объявите, что второе выполнение завершено, и всплывающее окно
  7. В этот момент первая функция входит в вершину стека, затем выполняется тело первой функции, код после вызова второй функции оказывается пустым, затем выполняется первая функция и появляется всплывающее окно.
  8. Основная функция на вершине стека выполняет последующий код

Итак, однопоточный JS, ссылаясь наВ движке JS стек вызовов для разбора и выполнения JS-кода уникален, все JS-коды выполняются в этом стеке вызовов в соответствии с последовательностью вызовов, и несколько функций не могут выполняться одновременно..

Что означает один поток?

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

Почему одинарная нить?
Первоначально JS был разработан для использования в браузерах, но как скриптовый язык в браузерах он требуетВзаимодействие с действиями пользователятак же какМанипулировать DOM, Если он многопоточный, нужно обратить внимание на синхронизацию состояния между каждым потоком.

Представьте, что две функции могут выполняться одновременно в js-движке, если две функции работают с одним и тем же объектом, какая из них будет преобладать?
Затем, при работе со структурой DOM, узел был удален в потоке A, а поток B все еще работает с узлом в то же время, что смущает.

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

В чем проблема?

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

function foo(){
  bar()
  console.log('after bar')
}
function bar(){
  while(true) {}
}

foo()

Например, в этом каштане функция bar вызывается в функции foo, затем функция foo должна дождаться завершения выполнения функции bar, прежде чем продолжить выполнение последующего кода.Однако функция bar является бесконечно исполняемой функцией. вы не можете вернуться, тогда функция foo ждет, пока все цветы не исчезнут.Нет никакого способа выполнить код позади.

Конечно, это экстремальная ситуация, но есть несколько распространенных случаев во фронтенд-бизнес-сценариях, которые здесь проблематичны:

  • Задержка таймера
  • сетевой запрос
  • веб-мероприятия и т. д.

Это наши общие异步操作,После срабатывания события результат не может быть получен сразу.Согласно предыдущему режиму работы браузер будет блокировать другие операции и ждать соответствующего результата.Если страница отображается в странице, страница застревает, что не допускается отличным приложением.

Синхронный асинхронный
Что касается синхронных и асинхронных операций, заимствование слов Великого Бога Пак Линга:
Общую операцию можно разделить на два этапа:

  1. позвонить
  2. получил ответ

Инициируйте звонок, и вы можете получить результат сразу за同步
Инициируя вызов, результат не может быть получен сразу, и для получения результата требуются дополнительные операции.异步

Итак, текущая модель异步操作проблематично

решение?
Суть проблемы в однопоточном режиме работы js движка, который фокусируется только на чем-то одном и должен быть [выполнен до завершения]
А те операции, которые вызывают проблемы, часто не могут получить результат напрямую, и должны пройти дополнительные операции, чтобы получить результат [асинхронная проблема]

идеи: вы можете поставить эти异步操作распространять其他模块, после получения результата обработки функция обратного вызова помещается в основной поток для выполнения.
Это основная идея Event Loop.

цикл событий - это просто способ решить асинхронную проблему Другие идеи включают в себя:

  • голосование
  • мероприятие

Web API's

Как упоминалось в предыдущей главе,异步操作Может быть передан за пределы движка JS其他模块процесс в браузере其他模块то естьWeb API模块

Web APIНа самом деле вышеизложенноеJS runtimeПредоставляет набор функций для различных сред размещения.

В браузере он в основном включает следующие возможности:

  • Event Listeners
  • HTTP request
  • Timing functions

Отлично покрывает вышеупомянутые случаи асинхронных проблем

Итак, на данный момент мы можем нарисовать следующий вид:

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

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

Вот вопрос?

Эти асинхронные операции отправляются наWeb APIПосле того, как модуль обработан, вы не можете отказаться от него,主线程Вам все равно нужно знать результат, чтобы делать последующие операции.Web APIКак уведомить основной поток после получения результата?

Для этого требуется помощь других модулей.

Это место упоминает主线程, а значит, есть и другие вспомогательные потоки.
Да, JS есть单线程执行Да, но это не означает, что ядро ​​браузера является однопоточным.
На самом деле в модуле веб-API есть несколько потоков, и каждый модуль обработки асинхронной операции соответствует потоку.
поток HTTP-запросов, поток обработки событий, поток обработки таймера и т. д.

очередь обратного вызова

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

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

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

Итак, кто знает, когда придет время?

Цикл событий знает.

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

Event Loop

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

До сих пор асинхронная операция, проходившая по кругу, наконец-то дала результат, успешно выполнилась и не блокировала другие операции.

overview

Полная схема выглядит следующим образом:

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

насчет нас

Передовая команда Kuaigou Taxi занимается обменом передовыми технологиями и регулярно публикует высококачественные статьи. Добро пожаловать, обратите внимание и лайкните.
Статья будет опубликована в паблике одновременно, если вы хотите получать актуальную информацию как можно быстрее, просто отсканируйте ее!

公众号二维码

Справочная статья