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+ (สมบูรณ์) |
| JIT บน iOS | ไม่จำเป็น | ไม่พร้อมใช้งาน (แปลความเท่านั้น) |
| ไบนารี | ~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 จะโหลด HBC โดยตรง โดยไม่ต้องแยกวิเคราะห์และคอมไพล์ ซึ่งช่วยเร่งการเริ่มต้นได้อย่างมาก: แทนที่จะแยกวิเคราะห์ JS นับพันบรรทัด (แบบอะซิงโครนัส) เอ็นจินจะอ่านรูปแบบไบนารีที่คอมไพล์ไว้ล่วงหน้า AOT ยังลดขนาดด้วย: ไบต์โค้ดมีขนาดกะทัดรัดกว่า JavaScript AST โดยเฉลี่ย 30% ข้อเสียของ 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% ภายใต้ภาระงานเดียวกัน — ซึ่งสำคัญอย่างยิ่งสำหรับอุปกรณ์ที่มี RAM 2-3 GB บน iOS ประโยชน์ยิ่งชัดเจนยิ่งขึ้น: เนื่องจาก JSC ไม่สามารถใช้ JIT ได้ Hermes จึงปรับปรุง TTI ได้ถึง 45% เมตริกอ้างอิงจากการทดสอบของ Meta กับแอป Facebook Lite ในโปรเจกต์จริง ประโยชน์จะแตกต่างกันไป: สำหรับหน้าจอธรรมดา (รายการ, ข้อความ) Hermes ให้การปรับปรุงที่มากกว่า สำหรับแอนิเมชันหนัก — น้อยกว่า เครื่องมือทำโปรไฟล์: React Native Profiler + hermes profile --heap
Hermes มีโปรไฟล์เลอร์หน่วยความจำในตัวที่เข้าถึงได้ผ่าน Chrome DevTools เชื่อมต่อกับแอปผ่าน Metro เปิดแท็บหน่วยความจำและเลือก Hermes (JavaScript) จากประเภทภาพรวม Hermes รองรับภาพรวมสามประเภท: Heap Snapshot (วัตถุทั้งหมด), Allocation Timeline (อายุของวัตถุ) และ Allocation Sampling (โปรไฟล์ตัวอย่าง) Hades GC ลดการหยุดชั่วคราวของ GC ให้เหลือน้อยที่สุด — โดยเฉลี่ยหนึ่งครั้ง 2-5ms ต่อ 10 วินาทีของการทำงาน เทียบกับการหยุด 10-20ms ของ JSC ในช่วงเวลาเดียวกัน
Hades GC คือตัวเก็บขยะใน Hermes ที่ออกแบบมาสำหรับสถานการณ์มือถือที่มีการหยุดชั่วคราวน้อยที่สุด ต่างจาก GC แบบ mark-sweep ใน JSC ตรงที่ Hades ใช้การเก็บขยะแบบพร้อมกัน (concurrent): ตัวเก็บขยะทำงานคู่ขนานกับเธรดหลัก โดยหยุดเธรดเฉพาะช่วงสั้น ๆ เท่านั้น Hades GC แบ่งฮีปเป็นรุ่น: รุ่นเด็ก (nursery) จะถูกเก็บถี่และรวดเร็ว (Scavenge) รุ่นแก่จะถูกเก็บน้อยครั้งกว่าและมีการหยุดชั่วคราวสั้นกว่า ขนาดฮีปสามารถกำหนดค่าได้: โดยค่าเริ่มต้น — 2/3 ของ RAM ที่แอปใช้ได้, เกณฑ์ขั้นต่ำ — 32 MB Hades ไม่ใช้วิธีการ stop-the-world: แม้การเก็บรุ่นแก่แบบเต็มก็ใช้เวลาไม่เกิน 5-8ms ตัวเก็บขยะได้รับการปรับให้เหมาะสมสำหรับสถานการณ์มือถือทั่วไป: วัตถุอายุสั้นจำนวนมาก (สตริงชั่วคราว, วัตถุ React fiber) วัตถุอายุยาวน้อย สำหรับแอปพลิเคชันที่มีการสร้างวัตถุจำนวนมาก (รายการ, แอนิเมชัน) 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 ให้เปลี่ยนแฟล็กและทำการสร้างใหม่แบบสะอาด
// 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 จะสร้างข้อยกเว้นระหว่างรันไทม์ 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 ปิดการใช้งาน Hermes หากไลบรารีของบุคคลที่สามต้องการ JSC — เปลี่ยนแฟล็กเป็น false และติดตั้ง Pods ใหม่
ไม่ Hermes ไม่ส่งผลต่อ Hot Reload / Fast Refresh ระหว่างการพัฒนา Metro จะรันบันเดิล JavaScript โดยไม่ต้องคอมไพล์ Hermes (JS ธรรมดา) ไบต์โค้ด Hermes จะถูกคอมไพล์สำหรับบิลด์ Release เท่านั้น ในโหมดดีบัก จะใช้ 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 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ