В большинстве статей о внутреннем устройстве Nodejs всегда говорится о границах C ++ / JS и их пересечении. Но большинство из них обычно не углубляется в объяснение того, что на самом деле означало пересечение границы C ++ / JS и что такое пересечение.
В этой статье мы подробно рассмотрим границы C ++ / JS, чтобы понять, что crossing
это влечет за собой.
Что мы извлечем из этой статьи: Node.js поддерживает более миллиона стартапов и компаний. Это наиболее часто используемый бэкэнд-фреймворк. Мы пользуемся им каждый день. Разработчики, обладающие навыками Node.js, пользуются большим спросом, поэтому глубокое изучение того, как работает Node.js, значительно расширит наш кругозор по Nodejs и будет уверенно создавать приложения Nodejs.
Совет. При создании приложений на Node.js вы можете совместно использовать общий код и управлять им в любом масштабе с помощью Bit. Вместо того, чтобы дублировать код, просто поделитесь им и синхронизируйте его. Попробуйте сами.
C ++ / JS: граница между двумя мирами
Все начинается с компилятора.
Во-первых, что такое компилятор?
Компилятор - это программа, которая переводит фрагмент кода в машинный код.
Большой!! into machine code
. Помни это.
Компиляторы - это сложные программы, они разбиты на части, каждая из которых выполняет определенную работу.
source code
|
v
lexical analyzer
|
v
parser
|
v
code generation
лексический анализатор: генерирует токены из исходного кода.
синтаксический анализатор: генерирует дерево AST (абстрактное синтаксическое дерево) из токенов.
генерация кода: генерирует машинный / ассемблерный код из AST.
Большинство компиляторов генерируют ассемблерный эквивалент исходного кода и оставляют ассемблеру самому собрать все в двоичный суп.
Nodejs использует движок v8 JS для компиляции и выполнения кода JS. Надеюсь, мы знаем, что такое v8.
в противном случае v8 - это высокопроизводительный компилятор JavaScript с открытым исходным кодом от Google.
Каждый раз, когда мы запускаем js-файл в Node.js следующим образом:
node script.js
Nodejs передает скрипт в v8, используя свои API. v8 компилирует код JS в предоставленном сценарии (script.js) и возвращает эквивалент сборки. Затем Node.js использует другой API v8 для запуска сгенерированного кода сборки.
Компилятор компилирует код в сборку и копирует его в память.
Глядя на изображение выше, код JS компилируется в код сборки.
Чтобы запустить скомпилированный код, он выделяет место в памяти, перемещает код в выделенное пространство и переходит в пространство памяти.
Теперь при переходе выполнение начинается с скомпилированного кода. Следовательно, он перешел границу.
Выполняемый сейчас код - это не код C ++, а код JS. Все сейчас в сборке.
Если выполнение скомпилированного JS-кода завершается, он возвращается к коду C ++.
Код C ++ и код JS здесь не означают исходный код C ++ или исходный код JS. Нет. Это ассемблерный код, сгенерированный компилятором из их исходных кодов, и это то, что выполняется. Вы можете произнести код C ++ и код JS, чтобы различать, какой ассемблерный код запускается.
Вызов из JS в C ++
Функции в исходном коде C ++ можно вызывать из JS-кода.
Пример:
// script.js let f = 90 function send() { var f= 100 } send() sendMe()
В этом коде мы определили функцию send
, но функции sendMe
нет.
Функция sendMe
будет определена в нашем приложении на C ++:
// v8_demo.cpp include "v8.h"; void sendMe() { cout << "Greetings from C++ land"; } int main() { Maybe<Local> result = v8::Script::Compile('script.js'); result->Run(); }
Примечание: приведенные выше фрагменты не запускаются. Это просто для демонстрационных целей.
Здесь у нас есть функция sendMe
.
Посмотри, что получится. При исполнении наша v8_demo.cpp
работает так:
MEMORY ; v8_demo.cpp x00 sendMe: x01 push ""Greetings from C++ land"" x02 call cout x03 ret x04 x05 main: x06 push "script.js" x07 call Compile x08 push eax x09 call Run x10 x11 x12 x13 x14 x15 x16 x17 x18 x19 x20
увидеть, что функция sendMe присутствует. Исполнение начинается с основного и продолжается вниз. На x07
script.js
компилируется и помещается в память.
MEMORY ; v8_demo.cpp x00 sendMe: x01 push ""Greetings from C++ land"" x02 call cout x03 ret x04 x05 main: x06 push "script.js" x07 ➥ call Compile x08 push eax x09 call Run x10 x11 ;script.js x12 mov 90,f x13 send: x14 push 100 x15 call send x16 call sendMe x17 x18 x19 x20
См. Наш script.js
ассемблерный код в памяти. :) Здесь нет кода C ++ или JS. Все в сборке. Как я сказал ранее, мы можем просто разграничить, например, вот код сборки из сценария C ++, а вот код сборки из сценария JS.
Итак, когда выполняется Run
x09
,
MEMORY ; v8_demo.cpp x00 sendMe: x01 push ""Greetings from C++ land"" x02 call cout x03 ret x04 x05 main: x06 push "script.js" x07 call Compile x08 push eax x09 ➥ call Run x10 x11 ;script.js x12 mov 90,f x13 send: x14 push 100 x15 call send x16 call sendMe x17 x18 x19 x20
он переходит в область памяти кода сборки JS x12
.
Примечание. Run - это API v8 для запуска скомпилированного кода JS после компиляции.
MEMORY ; v8_demo.cpp x00 sendMe: x01 push ""Greetings from C++ land"" x02 call cout x03 ret x04 x05 main: x06 push "script.js" x07 call Compile x08 push eax x09 call Run x10 x11 ;script.js x12 ➥ mov 90,f x13 send: x14 push 100 x15 call send x16 call sendMe x17 x18 x19 x20
Здесь код, который мы написали в script.js, выполняется в виде сборки.
Когда выполнение достигает x15 call send
, он переходит к x13 send:
и выполняет свой блок, после чего возвращается и вызывает sendMe
.
MEMORY ; v8_demo.cpp x00 sendMe: x01 push ""Greetings from C++ land"" x02 call cout x03 ret x04 x05 main: x06 push "script.js" x07 call Compile x08 push eax x09 call Run x10 x11 ;script.js x12 mov 90,f x13 send: x14 push 100 x15 call send x16 ➥ call sendMe x17 x18 x19 x20
Эта функция не была определена в нашем script.js
, но, поскольку она была определена в v8_demo.cpp
, теперь она доступна в памяти. Его можно вызвать, потому что ассемблерная форма script.js
и v8_demo.cpp
теперь выполняется на одном языке и в одном пространстве памяти.
Итак, выполнение переходит к x00 sendMe:
, началу функции sendMe
.
MEMORY ; v8_demo.cpp x00 ➥ sendMe: x01 push ""Greetings from C++ land"" x02 call cout x03 ret x04 x05 main: x06 push "script.js" x07 call Compile x08 push eax x09 call Run x10 x11 ;script.js x12 mov 90,f x13 send: x14 push 100 x15 call send x16 call sendMe x17 x18 x19 x20
:) Отображается Greetings from C++ land
!!
Итак, этот вид прыжка называется Crossing the C++/JS boundary
.
Аналогичным образом возможен вызов из C ++ в JS при условии, что функция определена в области JS.
Заключение
Понимаете, это довольно просто, никакой магии, ничего страшного. Всякий раз, когда вы слышите "Crossing C++/JS"
, всегда представляйте, как все работает в сборке и в одном и том же пространстве памяти.
В наших следующих статьях мы подробно рассмотрим, как работают некоторые основные API-интерфейсы Node.js:
- setTimeout
- process.nextTick
- setImmediate
- Обещать
- setInterval
Если у вас есть какие-либо вопросы относительно этого или чего-либо, что я должен добавить, исправить или удалить, не стесняйтесь комментировать, писать мне по электронной почте или в прямом сообщении. Спасибо !!! 👍