Membahas pola penulisan JavaScript yang paling kompatibel dengan Hermes, menghindari alokasi di hot path dan biaya runtime polymorphism, serta memanfaatkan profiling hints khusus Hermes untuk menemukan bottleneck.

Episode 14 menata arsitektur: boundary yang jelas, bundle termodularisasi, dan kode asing yang terisolasi. Sekarang kita bicara kecepatan. Hermes bukan V8 — ia interpreter-based, tanpa JIT, dan sangat peka terhadap bentuk kode yang kalian tulis. Kabar baiknya, aturan mainnya jelas dan bisa dipelajari.
Roadmap episode 15: pola kode JavaScript yang paling ramah Hermes, menghindari hot-path allocation dan biaya runtime polymorphism, lalu profiling hints khas Hermes untuk menemukan bottleneck.
Hermes mengeksekusi bytecode dengan interpreter. Tanpa JIT, kode tidak dipanasi dan dioptimalkan seperti di V8 — setiap eksekusi melewati jalur yang sama. Konsekuensinya:
Pola terbaik untuk Hermes adalah kode yang bentuknya bisa diprediksi. Pikiran ini menjadi benang merah semua tips di episode ini.
Satu konsekuensi menarik: optimasi yang menang di V8 belum tentu terasa di Hermes, dan sebaliknya. Mikro-benchmark yang menang telak di engine ber-JIT bisa saja datar di interpreter. Karena itu selalu uji pola kode pada engine yang benar-benar dipakai — tolak godaan menyalin tips performa dari engine lain tanpa verifikasi sendiri.
Konsistensi adalah segalanya. Ketika kalian membuat objek dengan properti yang sama setiap waktu, Hermes bisa mengikat akses properti dengan cepat. Contoh yang baik:
function buildItem(name, price) {
return { name, price, sold: false };
}
const items = [
buildItem("kopi", 15),
buildItem("teh", 10),
];Semua elemen punya bentuk identik. Bandingkan dengan membuat objek dengan kunci berbeda-beda atau menambahkan properti belakangan — setiap perubahan bentuk memaksa interpreter melakukan lookup yang lebih mahal. Kalau bisa, jadikan objek final secepatnya: definisikan semua properti di konstruktor, jangan tambahkan setelahnya.
Alokasi itu mahal — bukan karena pembuatannya, tapi karena menekan GC. Kode yang berjalan jutaan kali per detik, misalnya render loop, transformasi list, atau animasi, tidak boleh menciptakan objek sementara yang dibuang sesaat kemudian. Contoh yang sering bocor:
function render(rows) {
const out = [];
for (const row of rows) {
out.push({ text: row.label, height: row.h + 2 });
}
return out;
}Setiap iterasi menciptakan objek baru yang akan jadi sampah. Untuk hot path, pertimbangkan reuse buffer atau struktur yang sudah ada:
function renderInto(rows, out) {
out.length = 0;
for (const row of rows) {
out.push(row.label + "|" + (row.h + 2));
}
return out;
}Memakai array yang di-reset ulang menukar alokasi dengan pembaruan di tempat. Hasilnya: GC lebih tenang dan jank di frame rate hilang. Pola serupa berlaku untuk string concatenation di dalam loop — hindari membangun string panjang sepotong-sepotong di setiap iterasi.
Polymorphism di sini bukan soal class, melainkan bentuk objek yang dipanggil dengan cara berbeda. Ketika fungsi yang sama dipanggil dengan objek yang bentuknya berbeda-beda, Hermes tidak bisa mengoptimalkan akses propertinya. Ini disebut megamorphic call site, dan biayanya nyata:
function read(obj, key) {
return obj[key]; // bentuk objek tidak bisa diprediksi
}Kalau key selalu diambil dari kumpulan kecil yang sama, daftarkan nama properti secara eksplisit dan gunakan dispatch sederhana. Hal lain yang senada: jangan mencampur dua bentuk objek di dalam satu array, dan hindari mengubah tipe properti — misalnya dari angka menjadi string — pada objek yang dipakai berulang.
Sebagai gambaran, dua bentuk berbeda bisa muncul hanya karena satu objek dibangun lewat satu pola konstruksi dan objek lainnya lewat pola yang sedikit beda. Konsistensi semacam inilah yang sering menjadi pembeda kinerja antara kode yang rapi dan kode yang berantakan, bahkan di level mikro.
Info
Sekali lagi: interpreter menyukai kepastian. Setiap "mungkin begini atau begitu" di kode kalian diterjemahkan menjadi lookup yang lebih lambat saat runtime.
Hermes menyediakan jendela ke dalam dirinya sendiri lewat properti runtime. Panggil getRuntimeProperties() untuk melihat statistik seperti ukuran heap dan waktu pause GC:
const props = HermesInternal.getRuntimeProperties();
console.log(props["kGCHeapSize"]);
console.log(props["kGCTotalPauseTime"]);Untuk analisis lebih dalam, sambungkan Hermes ke Chrome DevTools, sebagaimana dibahas di episode 7, dan amati: profil CPU untuk menemukan fungsi yang paling banyak menyerap waktu, heap snapshot untuk mengukur alokasi, dan flame chart animasi untuk mendeteksi jank. Ingat siklus yang sehat: ukur dulu, hipotesiskan penyebabnya, perbaiki, lalu ukur lagi. Jangan pernah mengoptimasi berdasarkan dugaan.
Performa Hermes bukan misteri — ia interpreter yang jujur: beri kode bentuk yang konsisten, hindari alokasi di hot path, dan jauhi polymorphism, maka interpreter akan melayani kalian dengan baik. Gunakan statistik runtime dan DevTools untuk memvalidasi setiap keputusan optimasi.
Inti yang harus dibawa pulang:
getRuntimeProperties() dan DevTools sebelum dan sesudah mengoptimasi.Di episode 16 kita membuka kap mesin compiler: Hermes Compiler Internals — pipeline hermesc dari frontend, IR, optimizer, sampai code generation, cara bytecode dihasilkan dan diserialisasi, serta custom build flags dan optimization tiers. Sampai jumpa!