Как исполняется JavaScript: движок, JIT и запуск кода

Как исполняется JavaScript: движок, JIT и запуск кода Полезное

Движок JavaScript — это программа, которая читает ваш исходный код и превращает его в действия процессора. Именно движок, а не «интерпретатор из Блокнота», отвечает за то, как исполняется JavaScript. Ниже разберу, что происходит с кодом от файла до машинных инструкций на примере V8 (движок Chrome и Node.js), чем интерпретатор отличается от JIT-компилятора, почему язык называют интерпретируемым и как запустить JS прямо сейчас в REPL и онлайн-песочнице.

Сразу разведу три вещи, которые легко путают: язык (спецификация ECMAScript описывает синтаксис и семантику), движок (V8, SpiderMonkey, JavaScriptCore — исполняет код по этой спецификации) и среда выполнения (браузер или Node.js — дает движку API вроде DOM, файлов и таймеров). Спецификация не требует ни интерпретации, ни компиляции — это решает конкретный движок.

Почему JavaScript называют интерпретируемым

Ярлык «интерпретируемый» относится к реализации и к рабочему процессу, а не к самому языку. Исторически первые движки просто интерпретировали код построчно, и для разработчика это выглядит так до сих пор: нет отдельного шага сборки, вы отдаете движку исходный текст, а не заранее скомпилированный бинарник. В этом смысле рабочий цикл ближе к Python, чем к C++.

Но внутри современный движок давно не «чистый интерпретатор». V8 компилирует горячие участки в машинный код на лету. То есть JavaScript — интерпретируемый по способу поставки кода и по отсутствию AOT-сборки, но частично компилируемый по внутреннему механизму исполнения. Называть его «просто интерпретируемым» — упрощение; граница именно в этом.

Отсюда и путаница в старых статьях со словами «компилятор JavaScript» про Notepad++ или Sublime Text. Это текстовые редакторы, а не компиляторы: они подсвечивают синтаксис и дополняют код, но сами JS не исполняют. Исполнением занимается движок внутри браузера или Node.js.

Интерпретатор, компилятор и JIT — в чем разница

Три подхода отвечают на один вопрос по-разному: когда исходный код превращается в машинные инструкции.

Подход Когда переводит в машинный код Плюс Минус
Интерпретатор По ходу выполнения, инструкция за инструкцией Мгновенный старт, не нужна сборка Медленный на повторяющихся участках
Компилятор (AOT) Заранее, до запуска, целиком Быстрое выполнение готового бинарника Нужен шаг сборки, нет мгновенного старта
JIT (just-in-time) Во время выполнения, только для горячих участков Быстрый старт и высокая скорость на горячем коде Расход памяти и CPU на компиляцию, возможна деоптимизация

Движки JavaScript используют гибрид: интерпретатор для мгновенного старта плюс JIT-компиляция того кода, который выполняется часто. Так вы не ждете сборку, но и не платите скоростью на «горячих» функциях.

Как V8 исполняет код: от исходника до машинного кода

V8 — открытый движок Google, написанный на C++. Он стоит в Chrome, Edge, Opera, а также в серверных средах Node.js 24 LTS и Deno. Путь кода внутри выглядит так:

  1. Парсинг. Движок читает текст и строит AST — дерево, которое описывает структуру программы (функции, выражения, циклы).
  2. Генерация байткода. Компонент Ignition превращает AST в компактный байткод и сразу его исполняет. Это и есть интерпретатор V8 — он дает мгновенный старт без ожидания компиляции.
  3. Тиринг (постепенная оптимизация). V8 считает, как часто вызывается функция. «Горячий» код передается оптимизирующим компиляторам, которые переводят байткод в машинный код под конкретный процессор.
  4. Деоптимизация. Оптимизации строятся на предположениях о типах данных. Если предположение ломается (например, в функцию, всегда работавшую с числами, вдруг пришла строка), V8 откатывает функцию обратно на байткод и при необходимости оптимизирует заново.

Оптимизация в V8 многоуровневая. Ориентировочная схема компонентов на 2026 год:

Компонент V8 Роль Что делает
Ignition Интерпретатор Генерирует и исполняет байткод, быстрый старт
Sparkplug Базовый компилятор Быстро переводит байткод в машинный код без тяжелых оптимизаций
Maglev Оптимизирующий компилятор среднего уровня Умеренно оптимизирует горячие функции с небольшой задержкой
TurboFan Оптимизирующий компилятор верхнего уровня Агрессивно оптимизирует самый горячий код

Набор и порядок уровней зависят от версии V8, поэтому конкретные названия стоит сверять с текущим релизом (см. точки для фактчека). Ключевой принцип устойчив: чем чаще исполняется код, тем сильнее движок вкладывается в его оптимизацию.

Проследить тиринг можно флагами Node.js. Они показывают, какие функции оптимизируются и деоптимизируются:

node --trace-opt --trace-deopt hot.js

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

Минимальный пример: горячая функция

Сохраните файл hot.js и запустите его через node hot.js. Функция sum сначала исполняется байткодом Ignition, а после множества вызовов V8 переведет ее в машинный код.

function sum(n) {
  let acc = 0;
  for (let i = 0; i < n; i++) {
    acc += i;
  }
  return acc;
}

// первый вызов: код исполняет интерпретатор Ignition
console.log(sum(1000000)); // выведет 499999500000

// прогреваем функцию: после многих вызовов V8 оптимизирует sum
let last = 0;
for (let k = 0; k < 200; k++) {
  last = sum(1000000);
}
console.log(last); // снова 499999500000, но теперь это машинный код

В консоли обе строки дадут одно число:

499999500000
499999500000

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

Движки в браузерах и Node.js

V8 — не единственный движок. У каждого крупного браузера свой, и все они реализуют один стандарт ECMAScript, поэтому один и тот же код работает везде.

Движок Где стоит Разработчик
V8 Chrome, Edge, Opera, Node.js, Deno Google
SpiderMonkey Firefox Mozilla
JavaScriptCore (Nitro) Safari Apple

Важно не путать движок и среду выполнения. Движок исполняет JavaScript. Среда выполнения (runtime) добавляет вокруг него внешний мир: в браузере это DOM, fetch и события, в Node.js 24 — модули, доступ к файловой системе, сеть и цикл событий поверх того же V8. Один движок, разные среды — поэтому document.querySelector работает в браузере, но не в Node.js, а fs.readFile — наоборот.

Как запустить JavaScript прямо сейчас

Для эксперимента не нужен ни компилятор, ни сборка. Есть три быстрых способа.

1. Браузерная консоль. Откройте инструменты разработчика (F12 или Ctrl+Shift+I, в Safari сначала включите меню разработчика), вкладку Console, впишите строку и нажмите Enter:

[1, 2, 3, 4].filter(x => x % 2 === 0);

Консоль сразу покажет результат вычисления:

(2) [2, 4]

Это REPL — read-eval-print loop: движок читает выражение, вычисляет, печатает результат и ждет следующее. Удобно для проверки одной строки без файла.

2. REPL в Node.js. Установите Node.js 24 LTS и в терминале наберите node без имени файла — откроется интерактивная сессия:

$ node
Welcome to Node.js v24.x.x.
> 2 + 2
4
> const name = "otus"
undefined
> name.toUpperCase()
'OTUS'
> .exit

Здесь undefined после const name = "otus" — это нормально: объявление переменной не возвращает значения, REPL честно печатает undefined. Команда .exit (или Ctrl+D) закрывает сессию.

3. Онлайн-песочница. Если ставить Node.js не хочется, подойдут браузерные редакторы (песочницы) — CodePen, JSFiddle, PlayCode, Replit и подобные. Открываете страницу, пишете код в поле, видите вывод рядом. Под капотом это тот же движок браузера, просто с готовым интерфейсом. Для первых шагов этого достаточно; для реальных проектов лучше локальные Node.js плюс редактор кода, например VS Code или WebStorm.

Ошибку в любом из этих способов движок покажет сразу. Например, обращение к необъявленной переменной:

console.log(counter);

даст в консоли не число, а исключение:

ReferenceError: counter is not defined

Исправление — объявить переменную до использования:

let counter = 0;
console.log(counter); // 0

Выводы

  • JavaScript исполняет движок (V8, SpiderMonkey, JavaScriptCore), а не текстовый редактор; редакторы лишь помогают писать код.
  • «Интерпретируемый» — это про реализацию и рабочий цикл (нет AOT-сборки), а не про язык: внутри V8 горячий код компилируется в машинный.
  • V8 стартует через интерпретатор байткода Ignition, а часто вызываемые функции оптимизирует JIT-компиляторами (Sparkplug, Maglev, TurboFan) и при смене типов деоптимизирует.
  • Движок и среда выполнения — разные вещи: движок исполняет JS, а браузер или Node.js 24 дают ему API (DOM, файлы, сеть).
  • Запустить JavaScript можно за секунды — в консоли браузера, в REPL Node.js или в онлайн-песочнице.

Где применяется / связь с практикой

Понимание того, как движок исполняет код, — это не теория ради теории. Оно объясняет, почему стоит держать в функции стабильные типы данных (иначе V8 деоптимизирует ее), почему первый прогон медленнее прогретого и почему один и тот же код по-разному ведет себя в браузере и в Node.js. Эти вещи всплывают на любом собеседовании фронтендера и в первый же месяц реальной работы.

Освойте тему на практике

Системно освоить сам язык — переменные, функции, типы, работу с массивами и объектами — помогает курс «JavaScript Basic» в Otus: с практикой в REPL и разбором того, как код превращается в результат. Посмотреть формат и темы вживую можно на бесплатных открытых уроках Otus — там же отвечают на вопросы по старту в веб-разработке.

FAQ

JavaScript компилируется или интерпретируется?
И то, и другое. Разработчик отдает исходный код без шага сборки (как у интерпретируемых языков), но внутри движок JIT-компилирует горячие участки в машинный код. Чистого разделения тут нет.

Чем движок отличается от среды выполнения?
Движок (V8) исполняет сам JavaScript. Среда выполнения (браузер, Node.js) добавляет вокруг него API: DOM и fetch в браузере, файлы и сеть в Node.js. Поэтому не весь код работает в обеих средах.

Что быстрее для запуска кода — онлайн-песочница или Node.js?
Для одной проверки быстрее консоль браузера или онлайн-песочница: ничего ставить не нужно. Для проектов с файлами, зависимостями и отладкой удобнее локальный Node.js с редактором кода.

OTUS Журнал
Скидка 5% 14-20 сентября на курсы (popup)