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 به دلیل سیاستهای App Store (ممنوعیت تولید پویای کد)، JIT عملاً در دسترس نیست، بنابراین JSC در iOS فقط در حالت تفسیری کار میکند — عملکرد کاهش مییابد. JSC حجم باینری بزرگتری (حدود 10 MB) دارد و به دلیل زیرساخت JIT RAM بیشتری مصرف میکند. 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 AST JavaScript را تجزیه میکند، نمایش میانی HIR (Hermes Intermediate Representation) را تولید کرده و سپس بایتکد باینری HBC را منتشر میکند. نتیجه یک فایل با پسوند .hbc است که فقط شامل بایتکد بدون JavaScript اصلی است. Hermes runtime HBC را مستقیماً بدون تجزیه و کامپایل بارگذاری میکند. این کار راهاندازی را به شدت加速 میکند: به جای تجزیه هزاران خط JS (ناهمگام)، موتور یک فرمت باینری از پیش کامپایل شده را میخواند. 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 به لطف بایتکد فشرده و عدم وجود کتابخانههای JIT 28% کاهش مییابد. مصرف 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) را در انواع snapshot انتخاب کنید. Hermes از سه نوع snapshot پشتیبانی میکند: Heap Snapshot (همه اشیاء)، Allocation Timeline (طول عمر اشیاء) و Allocation Sampling (پروفایل انتخابی). Hades GC تعداد مکثهای GC را به حداقل میرساند — به طور متوسط یک مکث 2-5 میلیثانیه در 10 ثانیه کار در مقابل مکثهای 10-20 میلیثانیه در JSC در همان دوره.
Hades GC — زبالهرو در Hermes است که برای سناریوهای موبایل با حداقل مکث طراحی شده است. برخلاف GC mark-sweep در JSC، Hades از جمعآوری همزمان (concurrent) استفاده میکند: جمعآوریکننده به موازات رشته اصلی اجرا کار میکند و آن را فقط برای مدت کوتاه متوقف میکند. Hades GC heap را به نسلها تقسیم میکند: نسل جوان (nursery) اغلب و سریع جمعآوری میشود (Scavenge)، نسل قدیمی کمتر و با مکثهای کوچکتر جمعآوری میشود. اندازه heap قابل تنظیم است: به طور پیشفرض — 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 در بلاک project.ext.react.enableHermes مقدار enableHermes: true را تنظیم کنید. برای iOS: در Podfile از طریق use_react_native!(:path => config[:reactNativePath], :hermes_enabled => true) مقدار 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، برخی state-managerها)، BigInt (اعداد بزرگ)، Symbol.toStringTag، WeakRef و FinalizationRegistry. توابع eval و new Function در زمان اجرا استثنا ایجاد میکنند. callbackهای متدهای 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 را بررسی کنید. اگر کتابخانه شخص ثالث نیاز به JSC دارد، Hermes را غیرفعال کنید — برای این کار پرچم را به 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 پشتیبانی نمیکند — برای ساخت با Hermes از Expo Dev Client یا EAS Build استفاده کنید. سازگاری کتابخانهها را از طریق 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 از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید