Một Senior Engineer không bao giờ nói: "Tôi nghĩ đoạn code này chạy chậm". Họ nói: "Dựa trên Profiling, hàm này tốn 500ms để thực thi và chiếm 80% CPU".
1. Console Time & Performance API
Công cụ đơn giản nhất để đo nhanh một khối mã:
console.time("Array Process");
// Logic của bạn
console.timeEnd("Array Process");
// Chính xác hơn với Performance API
const start = performance.now();
doWork();
const end = performance.now();
console.log(`Execution time: ${end - start} ms`);2. Chrome DevTools Performance Tab
Đây là "vũ khí hạng nặng" của bạn.
- Mở Chrome DevTools -> Tab Performance.
- Nhấn nút Record (Hình tròn).
- Thực hiện thao tác bạn muốn đo lường trên trang web.
- Nhấn Stop.
Các chỉ số cần quan tâm:
- Long Tasks: Các khối mã chạy quá 50ms, thường gây ra hiện tượng giật lag (Jank).
- Flame Chart: Biểu đồ hình ngọn lửa cho thấy hàm nào đang gọi hàm nào và tốn bao nhiêu thời gian.
- Main Thread: Cột hiển thị các hoạt động của luồng chính JS.
3. Profiling Memory (Heap Snapshot)
Để tìm Memory Leaks, hãy dùng tab Memory:
- Chọn Heap Snapshot.
- Chụp 1 phát lúc ứng dụng vừa khởi động.
- Thực hiện thao tác (ví dụ: mở và đóng một Modal 10 lần).
- Chụp phát thứ 2.
- So sánh (Comparison) để xem object nào tăng lên mà không bị xóa.
4. Thử nghiệm: Tối ưu hóa vòng lặp
Hãy chạy bài Lab này để thấy sự khác biệt về hiệu năng giữa các cách viết code khác nhau.
5. Senior Note: "Premature Optimization"
Donald Knuth đã nói: "Tối ưu hóa sớm là nguồn gốc của mọi tội lỗi". Đừng tốn hàng giờ để tối ưu một hàm chỉ chạy 1 lần lúc khởi động và tốn 1ms. Hãy tập trung vào:
- Các thao tác lặp lại liên tục (Rendering).
- Các hàm xử lý dữ liệu lớn (Big Data).
- Các thao tác chặn người dùng (Blocking UI).
Tình huống thực tế & Phỏng vấn
Scenario: Ứng dụng bị giật lag khi gõ phím
Bối cảnh: Bạn có một thanh tìm kiếm (Search Bar) lọc danh sách 5000 sản phẩm. Khi người dùng gõ phím, giao diện bị đơ khoảng 1 giây.
Vấn đề: Sau khi dùng Profiling, bạn thấy hàm filterProducts chạy quá 300ms, chiếm dụng luồng chính (Main Thread) và ngăn cản trình duyệt vẽ lại UI cho ký tự vừa gõ.
Giải pháp Senior:
- Debouncing: Chỉ chạy lọc sau khi người dùng ngừng gõ 300ms.
- Offloading: Chuyển logic
filterProductssang một Web Worker để luồng chính rảnh tay phục vụ UI. - Phân tích kết quả: Sử dụng Performance Tab sau khi sửa để chứng minh "Long Tasks" đã biến mất.
Interview Question: Senior Level
Q: Tại sao việc đo lường (Benchmarking) bằng một vòng lặp for đơn giản đôi khi lại không phản ánh đúng hiệu năng thực tế trong JavaScript? (Gợi ý: Nhắc đến JIT Compilation và De-optimization).
Gợi ý đáp án
Đáp án: Do cơ chế JIT (Just-In-Time) của V8. Khi bạn chạy một vòng lặp hàng triệu lần, V8 sẽ tối ưu đoạn code đó thành mã máy cực nhanh. Nhưng trong ứng dụng thực tế, mã đó có thể được gọi với các kiểu dữ liệu khác nhau (Polymorphism) khiến V8 phải "de-optimize", làm cho nó chạy chậm hơn nhiều so với khi benchmark đơn lẻ. Senior cần đo lường trong bối cảnh thực tế của ứng dụng.
Tổng kết
Việc làm chủ công cụ Profiling giúp bạn tự tin hơn khi đưa ra các giải pháp kỹ thuật. Nó biến lập trình từ một môn "nghệ thuật cảm tính" thành một môn Khoa học máy tính thực thụ.