Thời điểm một tác vụ xảy ra và thời lượng tác vụ kéo dài là hai dữ liệu khác nhau. Date.now hữu ích cho timestamp, còn performance.now phù hợp để đo khoảng thời gian trong cùng ngữ cảnh chạy. Trộn hai nguồn hoặc dùng sai mục đích có thể làm số đo khó diễn giải.
1. Phép trừ đồng hồ hệ thống có thể phản ánh điều chỉnh giờ
// Simulated wall-clock readings, not a real clock adjustment.
const startMs = 10_000;
const endMs = 9_500;
console.log(endMs - startMs); // -500
Ví dụ mô phỏng hai lần đọc khi đồng hồ hệ thống lùi lại. Nó không thay đổi giờ trên máy. Date.now trả mili giây tính từ Unix epoch; số đo dựa trên đồng hồ hệ thống có thể chịu tác động của việc chỉnh giờ.
Timestamp vẫn cần thiết để đối chiếu log hoặc ghi nhận sự kiện. Nhưng nếu câu hỏi là “hàm này mất bao lâu?”, hãy chọn nguồn đo thời lượng, thay vì diễn giải mọi chênh lệch timestamp như thời gian thực thi.
2. Đo hai đầu bằng cùng một đồng hồ đơn điệu
const started = performance.now();
const value = await Promise.resolve('ready');
const elapsedMs = performance.now() - started;
console.log(value); // ready
console.log(Number.isFinite(elapsedMs)); // true
console.log(elapsedMs >= 0); // true
performance.now dùng đồng hồ đơn điệu, không bị điều chỉnh như đồng hồ lịch. Giá trị của nó có mốc riêng, không phải timestamp Unix để truyền trực tiếp vào new Date. Trong Node.js, mốc 0 đại diện lúc tiến trình bắt đầu.
Không lấy Date.now() trừ performance.now(), và không trừ trực tiếp hai giá trị performance.now từ hai tiến trình khác nhau. Cùng đơn vị mili giây chưa có nghĩa cùng mốc. Khi lưu log, có thể lưu timestamp và durationMs thành hai trường riêng, với ý nghĩa rõ ràng.
3. Truyền đồng hồ vào helper để kiểm thử ổn định
async function measureTask(task, now = () => performance.now()) {
const started = now();
const value = await task();
return { value, durationMs: now() - started };
}
const readings = [100, 125];
const result = await measureTask(
async () => 'done',
() => readings.shift()
);
console.log(result.value); // done
console.log(result.durationMs); // 25
Đồng hồ giả khiến test có đầu ra 25 ms cố định mà không cần chờ thật. Con số này kiểm chứng cách tính, không phải benchmark. Đồng hồ được truyền vào phải trả number hữu hạn, không giảm và dùng cùng đơn vị; helper minh họa coi đây là contract của bên gọi, không tự xác thực đồng hồ tùy biến.
task phải là hàm trả kết quả hoặc Promise đại diện toàn bộ tác vụ cần đo. Vì helper await task(), nó đo cả thời gian chờ Promise hoàn tất thành công. Nếu task ném lỗi hoặc reject, helper truyền lỗi ra bên gọi và không trả bản ghi duration; muốn ghi nhận thời lượng thất bại cần thiết kế thêm đường quan sát lỗi.
4. Xác định rõ số đo bao gồm công việc nào
Nếu task khởi chạy công việc rồi không return Promise của công việc đó, helper có thể kết thúc đo sớm. Tương tự, đo một lần gọi fetch chưa chắc bao gồm đọc body hoặc xử lý dữ liệu nếu những bước đó nằm ngoài hàm được đo. Đặt ranh giới theo câu hỏi cần trả lời.
Thời lượng quan sát được không tự đồng nghĩa CPU time. Nó có thể gồm chờ I/O, lịch thực thi và công việc khác trong khoảng đo. Một lần đo ngắn không đủ để kết luận tối ưu nhanh hơn; cần dữ liệu đại diện, nhiều mẫu và cách tổng hợp phù hợp.
Độ phân giải đồng hồ có thể bị giới hạn; hành vi trong lúc máy sleep cũng cần kiểm tra trên môi trường mục tiêu nếu sản phẩm phụ thuộc vào nó. Bài này không dùng số đo để chứng minh độ chính xác xuyên hệ điều hành hay so sánh máy khác nhau.
5. Checklist khi thêm số đo thời gian
- Cần thời điểm sự kiện hay thời lượng tác vụ?
- Hai đầu phép đo có cùng đồng hồ, đơn vị và ngữ cảnh?
- Promise được await có bao gồm toàn bộ công việc cần đo?
- Cần ghi nhận cả tác vụ thất bại hay chỉ thành công?
- Test dùng đồng hồ giả có được phân biệt rõ với benchmark thực tế?
Sáu khối mã Việt–Anh đã chạy bằng Node.js; kiểm tra bổ sung kết quả đồng bộ, tác vụ async và việc giữ nguyên lỗi. Chưa thử chỉnh đồng hồ hệ thống, sleep hoặc đo tải production.




Chưa có bình luận. Hãy là người đầu tiên chia sẻ ý kiến.