В браузере два разных движка: один рендерит HTML/CSS, другой выполняет JavaScript. Смотрите, как связаны Blink+V8, Gecko+SpiderMonkey и WebKit+JSCore.
«Движок браузера» — один из самых небрежно используемых терминов в веб-разработке, потому что на самом деле в браузере не один движок, а два, и они делают совершенно разную работу. Движок рендеринга превращает HTML и CSS в пиксели на экране. Движок JavaScript выполняет скрипты, которые делают страницу интерактивной. Они работают бок о бок, их создаёт один и тот же производитель, и о них постоянно говорят так, будто это одно и то же. Это не так, и разница важна не только терминологически: особенности движка JavaScript — это отдельный сигнал для идентификации, независимый от всего, что раскрывает движок рендеринга.
Ключевые выводы
- Браузер сочетает движок рендеринга (компоновки), который разбирает HTML/CSS и рисует пиксели, с отдельным движком JavaScript, который выполняет скрипты, — это два разных программных компонента.
- Три реальные пары: Blink + V8 (Chrome, Edge и другие браузеры на Chromium), Gecko + SpiderMonkey (Firefox) и WebKit + JavaScriptCore (Safari и, по правилам Apple, практически любой браузер на iOS).
- При загрузке страницы обе половины работают вместе: конвейер движка рендеринга «разбор → стили → компоновка → отрисовка» идёт параллельно с движком JavaScript, который выполняет скрипты, способные на лету менять этот же конвейер.
- У движков JavaScript есть собственный обнаруживаемый отпечаток — округление чисел с плавающей точкой, формулировки сообщений об ошибках, поведение
TypedArray, время прогрева JIT — независимо от того, какой движок рендеринга стоит рядом. - Проверка ядра браузера от BrowserInsight изучает обе половины: чтобы подделка выглядела убедительно, нужно подделать поведение и движка рендеринга, и движка JavaScript одновременно.
Два движка в одном браузере
Откройте любой браузер — и под капотом две отдельные программы совместно показывают вам страницу. Движок рендеринга (иногда его называют движком компоновки) читает HTML и CSS страницы и решает, что рисовать. Движок JavaScript читает и выполняет код <script> страницы — арифметику, работу с DOM, обработчики событий, всё динамическое.
Это действительно отдельные кодовые базы с разными задачами, разрабатываемые и версионируемые независимо друг от друга, даже внутри одного и того же браузерного проекта. Движок рендеринга понятия не имеет, как выполнять JavaScript; движок JavaScript понятия не имеет, как компоновать <div>. Их связывает слой биндингов, который позволяет JavaScript обращаться к DOM, поддерживаемому движком рендеринга, — и именно поэтому «движок JavaScript изменил страницу» и «движок рендеринга отрисовал страницу» — это два разных события, а не одно.
Наше руководство по движкам браузеров подробно рассматривает Blink, Gecko и WebKit как движки рендеринга. Эта статья — о той половине, которую то руководство лишь упоминает мимоходом: о движке JavaScript, работающем рядом с каждым из них.
Три реальные пары
Несмотря на десятки названий браузеров на рынке, реально используемых движков рендеринга и движков JavaScript всего по три, и каждый производитель сочетает свою собственную пару:
| Браузер(ы) | Движок рендеринга | Движок JavaScript |
|---|---|---|
| Chrome, Edge, Opera, Brave и другие браузеры на Chromium | Blink | V8 |
| Firefox | Gecko | SpiderMonkey |
| Safari и практически любой браузер на iOS/iPadOS | WebKit | JavaScriptCore (также известен как Nitro) |
Blink + V8. Оба движка разрабатывает Google. V8 компилирует JavaScript в машинный код через несколько уровней JIT-компиляции (just-in-time), обменивая время компиляции на скорость выполнения по мере того, как понимает, какие функции выполняются часто. Blink передаёт содержимое <script> движку V8 и предоставляет объекты DOM, которые может вызывать среда выполнения V8.
Gecko + SpiderMonkey. Пара Mozilla, развивающаяся в тандеме ещё со времён Netscape. Переработка JIT «Warp» в SpiderMonkey, выпущенная вместе с Firefox 83, перестроила систему уровней, снизив потребление памяти и ускорив реальные страницы, — хороший пример того, как движок JavaScript эволюционирует независимо от любых изменений движка рендеринга, происходящих в то же время.
WebKit + JavaScriptCore. Пара Apple, от которой браузерам на iOS никуда не деться. JavaScriptCore выполняет код на четырёх последовательных уровнях — интерпретатор LLInt, а затем JIT-компиляторы Baseline, DFG и FTL, — каждый из которых обменивает больше времени компиляции на большую скорость выполнения по мере того, как функция доказывает, что её стоит оптимизировать. Все четыре работают с единым форматом байт-кода, который WebKit переработал в 2019 году, сократив его расход памяти примерно вдвое.
Поскольку Apple требует, чтобы браузеры на iOS использовали WebKit, «Chrome для iPhone» на самом деле работает с интерфейсными привычками Blink поверх WebKit и JavaScriptCore — а не V8. Он лишь ощущается как Chrome. Под капотом оба движка — целиком от Apple. С iOS 17.4 европейский Закон о цифровых рынках (DMA) начал расшатывать это требование, но на практике браузеры на iOS по-прежнему работают на WebKit — и в ЕС, и за его пределами.
Оба движка за одну загрузку страницы
Одна загрузка страницы делает это разделение наглядным. Когда браузер получает страницу, происходит примерно следующее:
- Разбор — движок рендеринга читает исходный HTML и строит дерево DOM; читает CSS и строит дерево стилей.
- Начинается выполнение скрипта — как только движок доходит до тега
<script>(или срабатывает уже разобранный отложенный скрипт), управление берёт движок JavaScript, выполняя код, который может читать и переписывать DOM, только что построенный движком рендеринга. - Стили и компоновка — движок рендеринга объединяет DOM и CSS в дерево рендеринга и вычисляет положение и размер каждого блока с учётом всего, что изменил JavaScript.
- Отрисовка — движок рендеринга превращает эту компоновку в реальные пиксели.
Если скрипт изменяет DOM уже после первой отрисовки — добавляет элемент, меняет класс, анимирует стиль, — шаги 3 и 4 повторяются, но только для затронутой области. Этот цикл, в котором движок JavaScript и движок рендеринга по очереди передают друг другу управление, повторяется всё время, пока существует страница. Ни один из движков не может выполнить работу другого, но если один из них замедляется, тормозит весь цикл: движок рендеринга не может отрисовать содержимое, вычисление которого ещё не завершил застрявший движок JavaScript, а быстрый движок JavaScript бесполезен, если движок рендеринга не успевает быстро компоновать его результат.
Почему это разделение важно для идентификации и обнаружения
Это не просто архитектурная деталь — именно поэтому идентификация браузера должна проверять две вещи, а не одну.
Движок рендеринга оставляет поведенческие отпечатки через то, как он рисует: рендеринг шрифтов, поддержка CSS-возможностей, округление в компоновке. Движок JavaScript оставляет совершенно отдельный набор отпечатков через то, как он вычисляет: округление чисел с плавающей точкой в пограничных случаях, точную формулировку встроенных сообщений об ошибках (текст TypeError у V8, SpiderMonkey и JavaScriptCore тонко различается), поведение методов TypedArray и Array в пограничных случаях и время прогрева JIT — сколько вызовов требуется, прежде чем «горячая» функция будет оптимизирована. Всё это никак не связано с компоновкой.
Конкретный пример, который можно проверить в любой консоли: new Error().stack. V8 начинает строку с имени и текста ошибки, а каждый кадр записывает как at fnName (url:line:column). SpiderMonkey и JavaScriptCore этот заголовок опускают и пишут кадры как fnName@url:line:column. Один язык, один стандарт — и три разные формы строки, определяемые исключительно тем, какой движок JavaScript выполняет код, и видимые любому скрипту, который просто спросит.
Именно эта независимость и делает сигналы движка JavaScript ценными для обнаружения подделок. Скрипт, подделывающий строку user-agent или переопределяющий свойства navigator, чтобы выдать себя за другой браузер, меняет лишь то, что страница сообщает о себе, — но не меняет, какой движок JavaScript на самом деле выполняет код под капотом. Если страница заявляет, что она Safari на iOS, но формулировки сообщений об ошибках и поведение чисел с плавающей точкой в её движке JavaScript совпадают с V8, а не с JavaScriptCore, — это реальное несоответствие, которое скрипт может измерить напрямую, без всякого рендеринга.
Именно поэтому проверка ядра браузера от BrowserInsight не ограничивается определением движка рендеринга — она также проверяет поведение движка JavaScript. Убедительная подделка должна согласовать обе половины браузера, а это значительно сложнее, чем подменить одну строку.
Часто задаваемые вопросы
Blink — это то же самое, что V8?
Нет. Blink — это движок рендеринга Google: он разбирает HTML/CSS и рисует страницу. V8 — отдельный движок JavaScript Google: он выполняет скрипты. Оба входят в Chrome и другие браузеры на Chromium, оба созданы Google, но это разные кодовые базы с разными задачами.
Использует ли Firefox тот же движок JavaScript, что и Chrome?
Нет. Firefox сочетает Gecko (рендеринг) со SpiderMonkey (JavaScript) — собственным движком Mozilla, никак не связанным с V8 от Google. Chrome, Edge, Brave и другие браузеры на Chromium используют V8.
Какой движок JavaScript использует Safari?
JavaScriptCore, также известный как Nitro, — собственный движок Apple, сочетающийся с движком рендеринга WebKit. Поскольку Apple требует, чтобы браузеры на iOS использовали WebKit, браузеры на iPhone также работают на JavaScriptCore, независимо от того, каким браузером они себя называют. С iOS 17.4 европейский Закон о цифровых рынках разрешает на iOS альтернативные движки, но на практике почти каждый браузер на iOS по-прежнему поставляется с WebKit и JavaScriptCore.
Могут ли два браузера использовать один и тот же движок рендеринга, но разные движки JavaScript?
Среди сегодняшних основных браузеров — нет: каждый производитель поставляет свой движок рендеринга и движок JavaScript строго парой (Blink+V8, Gecko+SpiderMonkey, WebKit+JavaScriptCore). Технически смешивать их возможно, поскольку это отдельные проекты, но ни один массовый браузер так не делает.
Заключение
Движок браузера и движок JavaScript — не одно и то же, хотя их создаёт одна и та же горстка производителей, а браузер обычно называют одним именем. Blink сочетается с V8, Gecko со SpiderMonkey, WebKit с JavaScriptCore — три по-настоящему независимые пары, выполняющие две по-настоящему независимые задачи, сотрудничая при каждой загрузке страницы. Поскольку движок JavaScript оставляет собственный поведенческий след, отдельный от всего, что раскрывает движок рендеринга, настоящая проверка «что это за браузер» обязана смотреть на обе половины. Запустите проверку ядра браузера от BrowserInsight, чтобы узнать, какую именно пару движков реально использует ваш браузер.
Рекомендуем прочитать:


