NodeJS это интерпретатор или компилятор?
Если учитывать, что он работает на движке V8, который выполняет компиляцию JavaScript в машинный код, то это компилятор.
Но данные в интернете (статьи на хабре/вопрос-ответы на хабре/другие сайты) говорят иначе: либо строго интепретатор, либо компилятор и интепретатор одновременно (разве такое может быть?).
После вышесказанного я не понимаю, можно ли с полной уверенностью назвать NodeJS компилятором?
Ответы (3 шт):
Давайте разберём по пунктам:
- Node.js – это рантайм, среда выполнения для программ на языке JavaScript, который содержит в себе движок V8.
- V8 – это интерпретатор языка JavaScript с технологией JIT, Just-in-Time компиляции и VM, виртуальная машина, на которой полученный байт-код выполняется. Однако это в первую очередь интерпретатор, компиляция в машинный код происходит на лету, не формируется самодостаточного бинарного/байтового файла, который можно отдельно запускать вне V8 и рантайма, куда он встраивается, будь то Node.js или браузер.
- Можно сравнить с языком Java, программы на котором схоже обрабатывается и переводится в байт-код, однако этот процесс называется именно компиляцией, т.к полученный файл хотя запускается только лишь на JVM, виртуальной машине Джавы, однако более не требует исходного кода для работы. В принципе, аналогично можно было бы сделать и для JS, но он для этого не предназначен.
- Более того, JiT компиляция работает хитрым способом, предназначенным для языков со слабой и динамической типизацией – в процессе работы программы, анализируются используемые типы аргументов функций, и при должной статистике, части кода перекомпилируются под конкретные типы параметров, для повышения производительности (в V8 эти подходы называются Ignition и TurboFan). Согласитесь, это явно не классическая компиляция, где мы единожды получаем выходную программу и статически её выполняем в неизменном виде
:)
- Ещё обращу внимание, может кто не в курсе, сами языки не бывают компилируемыми или интерпретируемыми, ведь языки программирования это абстрактные наборы правил, и в теории любому языку можно разработать и интерпретатор, и компилятор, правда с разными усилиями, в зависимости от количества абстракций в спецификации языка.
Подробнее про режимы JiT компиляции
Понятнее будет объяснить через хронологию выполнения кода:
Изначально, при выполнении какого-то JS кода, сперва он транслируется в не-оптимизированный, но универсальный байт-код. Этот байт-код выполняется на движке V8, но работает медленно, т.к не зная о входящих типах аргументов, они все трактуются как что угодно, требуя повсеместного использования динамической диспатчеризацией, т.е резолвинге методов и операторов через словари прототипов объектов, что обеспечивает полиморфизм в условиях слабой динамической типизации.
Затем, со сбором статистики, выполняются эвристические правила, которые оценивают, что вот эти функции работают, например, только с числами, следовательно здесь можно сразу вызывать арифметические операции, и в новом оптимизированном байт-коде прописывается указатель на соответствующую пользовательскую или внутреннюю функцию. Соответственно, так мы сильно сокращаем работу с обращением в словари в поисках значений строковых имён атрибутов, что и приводит к заметному приросту производительности.
Полученная новая версия байт-кода можно сказать написана на том же языке, что и прежняя, однако является более эффективной её реализацией (примерно как сортировка пузырьком и быстрая/слиянием). Новая версия байт-кода функции выполняется в том же самом процессе V8, просто заменяет прежнюю версию, и последующие обращения к функции будут эффективнее.
Кстати, стандартный интерпретатор Питона, CPython, работает аналогично первой части – он тоже транслирует исходный текст программы в байт-код. Также существует альтернативная имплементация, которая содержит JIT компиляцию: PyPy
Языки программирования уже давно однозначно не делятся на интерпретируемые и компилируемые. Так и JS нельзя отнести ни к одной из этих категорий.
Поскольку он принимает код на человекочитаемом языке и не производит файл с результатом компиляции, я считаю, что он является интерпретатором.
Если не ошибаюсь, для языков, исполняющих промежуточный байткод (джава и C#) этот исполнитель вообще принято называть виртуальной машиной. Но поскольку в js на вход попадает исходный код, а не промежуточный, я за интерпретатор.
Как вы правильно заметили Node.js использует V8:
Node.js runs on the V8 JavaScript engine...
А V8 основан на интерпретаторе и компиляторе:
In 2017, V8 shipped a brand-new compiler pipeline, consisting of Ignition (the interpreter) and TurboFan (the optimizing compiler).
Причём TurboFan настоящий оптимизирующий компилятор с кодогенерацией, распределением регистров и прочими атрибутами "нормальных" компиляторов, вроде C и C++.