Hermes — е JavaScript двигател с AOT компилация (Ahead-of-Time), разработен от Meta за React Native и оптимизиран за мобилни устройства с ограничена памет. Според официалния блог на Meta Engineering (2022), Hermes намалява времето за стартиране на приложението с 20-50% и намалява размера на пакета с 30-40% в сравнение с JavaScriptCore. За разлика от V8 или JSC, Hermes не използва JIT компилация на устройството — целият JavaScript се компилира в байткод на етапа на изграждане чрез Hermes CLI. Това е особено важно за iOS, където JIT компилацията е ограничена от политиките на App Store.
Основни точки
Hermes — е компактен JavaScript двигател с отворен код (MIT лиценз), създаден от Meta за React Native и оптимизиран за работа на мобилни устройства с ограничени ресурси. Основната иновация на Hermes е отказът от JIT компилация в полза на AOT (Ahead-of-Time). На етапа на изграждане на React Native приложение, Metro Bundler предава компилирания JavaScript на Hermes CLI, който го преобразува в HBC байткод (Hermes ByteCode). Този байткод се изпълнява директно от двигателя без допълнителна компилация на устройството. Този подход осигурява предвидима производителност: няма „загряване" на JIT, няма паузи за компилация, няма допълнителен разход на батерия. Hermes е проектиран, като се вземат предвид ограниченията на мобилните устройства: малко RAM (1-4 GB), ограничена консумация на енергия и необходимост от бърз студен старт. Първото публично издание на Hermes беше през 2019 г., а от React Native 0.70 (2022) двигателят стана стандарт на Android.
JavaScriptCore (JSC) — стандартният WebKit двигател, използван от Safari и React Native преди версия 0.70. JSC поддържа JIT компилация, което осигурява висока производителност за сложни JavaScript операции. Въпреки това JIT изисква загряване: първите секунди кодът работи по-бавно (интерпретиран режим), след което JIT компилира горещите части. На iOS JIT е практически недостъпен поради политиките на App Store (забрана за динамично генериране на код), така че JSC на iOS работи само в интерпретиран режим — производителността спада. JSC има по-голям двоичен размер (около 10 MB) и консумира повече RAM поради JIT инфраструктурата. Hermes не зависи от JIT, което осигурява предвидима производителност веднага след стартиране (студен старт). JSC поддържа по-пълно стандарта ECMAScript (включително Proxy, BigInt, Reflect), но с цената на по-голяма консумация на ресурси. За React Native проекти, където студеният старт и малкият размер са критични — Hermes е за предпочитане. За проекти с тежки JS изчисления (игри, WebGL) — JSC може да осигури по-висока пикова производителност.
| Параметър | Hermes | JavaScriptCore |
|---|---|---|
| Компилация | AOT (на етапа на изграждане) | JIT + Интерпретиран (на устройството) |
| Студен старт | 20-50% по-бърз | Базово ниво |
| Размер на пакет | 30-40% по-малък | Базово ниво |
| Консумация на RAM | 20-30% по-малко | Базово ниво |
| ECMAScript | ES2020 (ограничения) | ES2022+ (пълен) |
| iOS JIT | Не се изисква | Недостъпен (само интерпретиран) |
| Двоичен | ~3 MB | ~10 MB |
AOT компилация (Ahead-of-Time) в Hermes се извършва на два етапа. На първия етап Metro Bundler събира JavaScript файловете в единен пакет и го предава на Hermes CLI (инструментът hermesc). На втория етап hermesc парсира JavaScript AST, генерира междинно представяне HIR (Hermes Intermediate Representation) и след това емитира двоичен HBC байткод. Резултатът е файл с разширение .hbc, който съдържа само байткод без оригиналния JavaScript. Hermes runtime зарежда HBC директно, без парсване и компилация. Това радикално ускорява стартирането: вместо да парсва хиляди JS редове (async), двигателят чете предварително компилиран двоичен формат. AOT също намалява размера: байткодът е средно с 30% по-компактен от JavaScript AST. Недостатъкът на AOT — невъзможността за изпълнение на eval, new Function или динамично require по време на изпълнение — всички модули трябва да бъдат известни на етапа на изграждане.
# Инсталирайте Hermes CLI самостоятелно
npm install hermes-engine
# Компилирайте JS в HBC байткод
npx hermesc -emit-binary -out bundle.hbc bundle.js
# Статистика на байткода
npx hermesc -dump-bytecode bundle.hbc # shows HBC instructions
# Размер на оригинален JS срещу HBC
wc -c bundle.js # 2,300,000 bytes
wc -c bundle.hbc # 1,450,000 bytes (37% reduction)
Производителността на Hermes се измерва с три ключови метрики: Time-To-Interactive (TTI), размер на APK/IPA и консумация на RAM. Според Meta, на Android Hermes намалява TTI с 34% в сравнение с JSC: от 4.2 секунди на 2.8 секунди на устройство от среден сегмент (Moto G7). Размерът на APK намалява с 28% благодарение на компактния байткод и липсата на JIT библиотеки. Консумацията на RAM е средно с 22% по-ниска при същото натоварване — това е особено важно за устройства с 2-3 GB RAM. На iOS предимството е още по-голямо: тъй като JSC не може да използва JIT, Hermes дава подобрение на TTI до 45%. Метриките се основават на тестове на Meta с приложението Facebook Lite. В реални проекти предимството варира: за прости екрани (списъци, текст) Hermes дава по-голямо подобрение, за тежки анимации — по-малко. Инструмент за профилиране: React Native Profiler + hermes profile --heap.
Hermes включва вграден профилиращ инструмент за памет, достъпен чрез Chrome DevTools. Свържете се с приложението чрез Metro, отворете раздела Memory и изберете Hermes (JavaScript) в типовете моментни снимки. Hermes поддържа три типа моментни снимки: Heap Snapshot (всички обекти), Allocation Timeline (живот на обектите) и Allocation Sampling (селективен профил). Hades GC намалява броя на GC паузите до минимум — средно една пауза от 2-5ms на 10 секунди работа срещу паузи от 10-20ms при JSC за същия период.
Hades GC — е събирачът на отпадъци в Hermes, проектиран за мобилни сценарии с минимални паузи. За разлика от mark-sweep GC в JSC, Hades използва конкурентно (concurrent) събиране: събирачът работи паралелно с основната нишка на изпълнение, спирайки я само за кратки периоди. Hades GC разделя купчината на поколения: младото поколение (nursery) се събира често и бързо (Scavenge), старото поколение се събира по-рядко и с по-малки паузи. Размерът на купчината е конфигурируем: по подразбиране — 2/3 от наличната RAM на приложението, минимален праг — 32 MB. Hades не използва stop-the-world подход: дори пълното събиране на старото поколение отнема не повече от 5-8ms. Събирачът е оптимизиран за типичния мобилен сценарий: много краткоживеещи обекти (временни низове, React fibre обекти), малко дългоживеещи. За приложения с интензивно създаване на обекти (списъци, анимации) Hades осигурява по-плавен FPS в сравнение с JSC.
Включването на Hermes зависи от версията на React Native и платформата. От React Native 0.70 Hermes е включен по подразбиране за Android в нови проекти. За iOS Hermes е опционален. За включване на Android: във файла android/app/build.gradle задайте enableHermes: true в блока project.ext.react.enableHermes. За iOS: задайте hermes_enabled на true в Podfile чрез use_react_native!(:path => config[:reactNativePath], :hermes_enabled => true). След включване изпълнете pod install. За съществуващи проекти проверете съвместимостта на библиотеките: Hermes не поддържа Proxy, eval и някои ES2021 функции. Използвайте npx react-native info за проверка на конфигурацията. За превключване между Hermes и JSC променете флага и изпълнете clean rebuild.
// android/app/build.gradle — включете Hermes
project.ext.react = [
enableHermes: true,
cliPath: "node_modules/react-native/cli.js"
]
// iOS/Podfile — включете Hermes на iOS
require_relative '../node_modules/react-native/scripts/react_native_pods'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
target 'MyApp' do
config = use_native_modules!
use_react_native!(
:path => config[:reactNativePath],
:hermes_enabled => true
)
end
Основните ограничения на Hermes са свързани с отказа от JIT. Hermes не поддържа: Proxy и Reflect API (използвани в MobX, Vue, някои мениджъри на състояние), BigInt (големи числа), Symbol.toStringTag, WeakRef и FinalizationRegistry. Функциите eval и new Function генерират изключение по време на изпълнение. Обратните извиквания на методите Array.prototype.flat и flatMap с аргумент this работят с ограничения. ISO 8601 форматите за дата с часови зони не се обработват напълно. Повечето от тези ограничения не засягат типичните React Native приложения: React и React Native използват ограничен набор от ES функции. Ако библиотека изисква Proxy (например MobX 6+ с Proxy), използвайте configure({ useProxies: false }) или изберете алтернатива. За проверка на съвместимостта на съществуващия код изпълнете npx hermesc -check върху вашия пакет — ще покаже списък на неподдържаните функции.
Често задавани въпроси
В конзолата на приложението изпълнете console.log(global.HermesInternal). Ако обектът HermesInternal съществува — приложението работи на Hermes. Алтернативно: console.log(global.HermesInternal?.getRuntimeProperties()) — ще покаже версията на двигателя и параметрите на GC. В Release версии HermesInternal може да бъде недостъпен за минимизиране на размера.
Проверете настройките на Podfile: Hermes на iOS изисква New Architecture (Fabric Renderer). Задайте :hermes_enabled => true, изпълнете pod install --repo-update. Ако проектът се актуализира от React Native под 0.70, проверете съвместимостта на библиотеките с New Architecture. Изключете Hermes, ако библиотека на трета страна изисква JSC — за целта променете флага на false и преинсталирайте Pods.
Не, Hermes не влияе на Hot Reload / Fast Refresh. По време на разработка Metro стартира JavaScript пакета без Hermes компилация (обикновен JS). Hermes байткод се създава само за Release версии. В Debug режим се използва стандартен JavaScriptCore или Hermes в интерпретиран режим. Скоростта на Hot Reload не се променя, когато Hermes е включен в конфигурацията — превключването става само на етапа на производствено изграждане.
Да, от Expo SDK 45 Hermes се поддържа за managed workflow. В app.json задайте "jsEngine": "hermes". За bare workflow Hermes работи като в обикновен React Native проект. Expo Go не поддържа Hermes — използвайте Expo Dev Client или EAS Build за версии с Hermes. Проверете съвместимостта на библиотеките чрез expo doctor.
Използвайте React Native Performance Monitor (FPS метрики) и Hermes Profiling Tools. Създайте две версии на приложението — с Hermes и JSC — на едно и също устройство. Измерете: студен старт (от кликване на иконата до първия интерактивен екран), TTI (Time-To-Interactive), размер на APK/IPA и пикова консумация на RAM. Изпълнете тестовете поне 3 пъти за всяка конфигурация. Типично предимство на Hermes: старт 20-40% по-бърз, RAM 15-25% по-малко.
Резюме
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също