Performance Profiling — Debugging

Performance Profiling Debugging bukan hanya tentang error — aplikasi yang lambat juga perlu di-debug. Performance profiling membantu menemukan bottleneck di apl

Performance Profiling

Debugging bukan hanya tentang error — aplikasi yang lambat juga perlu di-debug. Performance profiling membantu menemukan bottleneck di aplikasi.

Performance Panel di DevTools

  1. Buka DevTools → tab Performance
  2. Klik Record (atau Ctrl+E)
  3. Lakukan aksi yang ingin diukur
  4. Klik Stop
  5. Analisis hasilnya

Membaca Flame Chart

Flame chart menampilkan apa yang browser lakukan selama recording:

Waktu →
├── Task (50ms)
│   ├── Parse HTML (5ms)
│   ├── Evaluate Script (30ms)
│   │   ├── fetchData() (20ms)
│   │   └── renderList() (10ms)
│   └── Layout (10ms)
│       └── Style recalculation (5ms)
└── Paint (3ms)

Flame Chart Anatomy

<style>.lbl{font:12px sans-serif;fill:#0f172a}.sub{font:10px sans-serif;fill:#475569}.tip{font:10px sans-serif;fill:#0369a1}.bar{stroke:#1e293b;stroke-width:0.5}</style> Flame chart: stack depth vertikal, waktu horizontal main() — total 100ms, self 5ms renderPage() — total 60ms, self 10ms fetchData() — total 40ms, self 5ms parseJSON — self 25ms compile — self 40ms ← hotspot parseResp applyData Lebar = total waktu. compile paling lebar → optimize di sini. Self time vs Total time Total time = self + waktu semua child calls (lebar bar) Self time = waktu HANYA di function itu, tidak termasuk child (berat sendiri) Optimasi: cari function dengan SELF TIME tertinggi — itu bottleneck sebenarnya.

Cara baca cepat:

Di Chrome Performance panel, beralih ke Bottom-Up view untuk list function sorted by self time descending — langsung fokus ke hotspot tanpa harus scan flame chart manual.

Mengukur dengan JavaScript

performance.now()

const start = performance.now();

// ... operasi yang ingin diukur ...
const data = processLargeArray(items);

const end = performance.now();
console.log(`Waktu: ${(end - start).toFixed(2)}ms`);

Performance API

// Mark titik waktu tertentu
performance.mark("fetch-start");

await fetch("/api/data");

performance.mark("fetch-end");

// Ukur jarak antara dua mark
performance.measure("fetch-duration", "fetch-start", "fetch-end");

const measures = performance.getEntriesByName("fetch-duration");
console.log(`Fetch: ${measures[0].duration.toFixed(2)}ms`);

Masalah Performance Umum

1. Layout Thrashing

// ❌ Membaca dan menulis DOM bergantian (layout thrashing)
for (const el of elements) {
  const height = el.offsetHeight;    // READ → trigger layout
  el.style.height = height * 2 + "px"; // WRITE → invalidate layout
  // Loop berikutnya: READ lagi → layout lagi!
}

// ✅ Batch reads, then batch writes
const heights = elements.map(el => el.offsetHeight);  // Batch READ
elements.forEach((el, i) => {
  el.style.height = heights[i] * 2 + "px";  // Batch WRITE
});

2. Memory Leak

// ❌ Event listener tidak di-cleanup
useEffect(() => {
  window.addEventListener("resize", handleResize);
  // Lupa cleanup → listener terus menumpuk!
}, []);

// ✅ Cleanup saat unmount
useEffect(() => {
  window.addEventListener("resize", handleResize);
  return () => window.removeEventListener("resize", handleResize);
}, []);

3. Rendering Berlebihan

// ❌ Render ulang seluruh list saat satu item berubah
function TodoList({ items }) {
  return items.map(item => <TodoItem key={item.id} {...item} />);
}

// ✅ Memo untuk mencegah re-render yang tidak perlu
const TodoItem = React.memo(function TodoItem({ id, text, done }) {
  return <div>{text}</div>;
});

Lighthouse

Lighthouse adalah tool audit bawaan Chrome yang mengukur performa secara keseluruhan:

  1. DevTools → tab Lighthouse
  2. Pilih kategori (Performance, Accessibility, dll)
  3. Klik Analyze page load

Metrics utama:

Memory Panel

Untuk debugging memory leak:

  1. DevTools → Memory tab
  2. Heap snapshot — foto alokasi memory saat ini
  3. Allocation timeline — track alokasi seiring waktu

Cari object yang terus bertambah tapi tidak di-garbage collect.

console.time untuk Profiling Cepat

console.time("render");
renderComponent();
console.timeEnd("render");  // render: 23.456ms

// Atau gunakan console.profile (lebih detail)
console.profile("my-function");
myHeavyFunction();
console.profileEnd("my-function");
// Hasilnya muncul di Performance panel

Tips

  1. Jangan optimize prematur — ukur dulu, optimize yang benar-benar bermasalah
  2. Gunakan production build saat profiling — development mode lebih lambat
  3. Test di device nyata — laptop developer tidak merepresentasikan user
  4. Target 60fps — setiap frame harus selesai dalam ~16ms
  5. Lighthouse score bukan segalanya — user experience yang penting