Episode penutup menyatukan seluruh materi: mengukur performa dengan bukti, menghindari kebocoran memory, menerapkan pola debounce dan lazy loading, serta menyusun kode siap produksi dengan keamanan, pengujian, dan release yang terstruktur. Kalian menyelesaikan perjalanan Belajar JavaScript.

Selamat — kalian sudah sampai di episode terakhir. Dua puluh satu episode membangun pemahaman kalian dari sintaks dasar sampai tooling modern. Episode 22 menutup perjalanan dengan dua tema yang menentukan kualitas aplikasi di dunia nyata: performance dan readiness.
Performance berarti aplikasi tidak hanya berfungsi, tapi berfungsi cepat dan stabil — memuat ringan, merespons mulus, dan tidak bocor memory seiring waktu. Readiness berarti kode kalian aman, diuji, dan dirilis secara terstruktur. Keduanya adalah pembeda antara prototipe dan aplikasi produksi. Pegang satu prinsip sejak awal: jangan mengoptimasi tanpa bukti — ukur dulu, temukan masalah yang nyata, baru optimasi.
Sebelum mengubah apa pun, ukur. performance.now memberi waktu yang presisi:
function prosesData(angka) {
let total = 0;
for (const nilai of angka) {
total += nilai * 2;
}
return total;
}
const mulai = performance.now();
const hasil = prosesData([1, 2, 3, 4, 5]);
const selesai = performance.now();
console.log(`Hasil: ${hasil}, durasi: ${selesai - mulai} ms`);Alat yang sudah kalian kenal dari episode 19 kembali berguna: tab Performance di DevTools merekam sesi dan menunjukkan di mana waktu benar-benar terbuang. Cari long tasks yang memblokir halaman, lalu periksa fungsi atau layout yang mendominasi. Hasil pengukuran menentukan prioritas — terkadang optimasi yang paling "keren" justru tidak berdampak apa pun pada aplikasi nyata.
Akses dan manipulasi DOM jauh lebih lambat daripada operasi di memori. Kumpulkan perubahan dan pasang sekaligus:
const kontainer = document.querySelector("#daftar");
const fragmen = document.createDocumentFragment();
for (let i = 1; i <= 100; i++) {
const item = document.createElement("li");
item.textContent = `Item ${i}`;
fragmen.append(item);
}
kontainer.append(fragmen);document.createDocumentFragment() menampung elemen di memori terlebih dahulu, lalu dipasang sekaligus. Tanpa ini, 100 penambahan berarti 100 kali memicu render; dengan fragment, browser merender sekali. Prinsip yang sama berlaku untuk reflow — perhitungan ulang layout yang mahal: kumpulkan perubahan style dalam satu batch, misalnya kotak.style.display = "none", lalu ubah class, baru tampilkan kembali, sehingga terjadi satu batch, bukan tiga reflow terpisah.
JavaScript mengelola memory dengan garbage collection — objek yang tidak lagi bisa diakses dibersihkan otomatis. Kebocoran memory terjadi ketika objek yang seharusnya sudah mati tetap bisa diakses, sehingga GC tidak berani membersihkannya. Penyebab paling umum di aplikasi web:
Setiap addEventListener memegang referensi ke handler. Jika elemen dihapus tapi listener tidak dibuang, referensi tetap hidup:
function buatKartu() {
const tombol = document.querySelector("#tombol");
function handler() {
console.log("Diklik");
}
tombol.addEventListener("click", handler);
return function hapus() {
tombol.removeEventListener("click", handler);
};
}
const bersihkan = buatKartu();
bersihkan();tombol.removeEventListener("click", handler) membuang listener dengan handler yang sama persis — itu sebabnya handler harus disimpan dalam variabel, bukan ditulis anonim inline. Fungsi hapus yang dikembalikan memberi kontrol kapan pembersihan terjadi.
Operasi mahal yang dipicu sering — pencarian saat mengetik, scroll, resize — bisa membanjiri aplikasi. Debounce menunda eksekusi sampai jeda aktivitas; throttle membatasi eksekusi maksimal satu kali per interval:
function debounce(fungsi, jeda) {
let timer = null;
return function (...argumen) {
clearTimeout(timer);
timer = setTimeout(() => {
fungsi(...argumen);
}, jeda);
};
}
const cari = debounce((kata) => {
console.log("Mencari:", kata);
}, 300);Memuat seluruh aplikasi sekaligus memperlambat kunjungan pertama. Code splitting memecah bundle menjadi bagian yang dimuat sesuai kebutuhan:
async function muatModulBerat() {
const modul = await import("./modul-berat.js");
return modul.proses();
}
tombol.addEventListener("click", () => {
muatModulBerat().then(console.log);
});Kode produksi wajib mempertimbangkan keamanan. Dua aturan yang paling sering dilanggar:
innerHTML — celah XSS. Selalu pakai textContent atau escape HTML.HttpOnly.function teksAman(teks) {
const div = document.createElement("div");
div.textContent = teks;
return div.innerHTML;
}div.textContent = teks membuat browser men-escape karakter khusus, sehingga <script> berubah menjadi teks biasa yang aman ditampilkan. Pola ini adalah trik sederhana untuk menampilkan input pengguna tanpa membuka celah.
Kode siap produksi juga berarti proses yang terstruktur:
major.minor.patch — untuk perubahan yang breaking, fitur, dan perbaikan.Semua alatnya sudah dibahas di episode 20 dan 21: lint dan format otomatis, build reproducible dengan lockfile, dan npm scripts yang bisa dipanggil CI. Menggabungkannya menjadi pipeline rilis adalah langkah terakhir menuju produksi.
Episode 22 menutup perjalanan kalian: mengukur performa dengan performance.now dan tab Performance, mengoptimasi DOM dengan batching, mencegah kebocoran memory dengan membuang listener, menerapkan debounce dan lazy loading, serta menyusun kode produksi yang aman, teruji, dan dirilis terstruktur.
Inti yang harus dibawa pulang:
removeEventListener harus memakai handler yang sama persis.Ini adalah akhir dari series Belajar JavaScript. Dari episode 0 yang menyiapkan environment sampai episode 22 yang menyiapkan produksi, kalian telah membangun fondasi lengkap: sintaks, struktur data, fungsi, DOM, asynchronous, tooling, dan performa. Perjalanan sebenarnya dimulai sekarang — terapkan semua yang kalian pelajari di project sungguhan, dan teruslah menulis kode setiap hari. Selamat berkarya!