Đo lường thời gian thực hiện hàm trong Javascript một cách thanh lịch

Đo lường thời gian thực hiện hàm trong Javascript một cách thanh lịch

Tin ngắn hàng ngày dành cho bạn
  • Lại có thêm một công cụ hỗ trợ tìm kiếm nhanh lịch sử gõ lệnh nè mọi người: atuinsh/atuin.

    Điều thú vị là nó dùng SQLite để lưu trữ. Ngoài ra còn cung cấp tính năng đồng bộ hóa (mã hóa) hoàn toàn lịch sử giữa các máy với nhau nữa. Hay ghê 🤓

    » Xem thêm
  • Mình thấy ấn tượng với mô hình gemma-3n-E4B của nhà Google ghê. Đây là một trong những mô hình hứa hẹn mang các mô hình ngôn ngữ lớn xuống chạy trên thiết bị di dộng hoặc web hoặc nhúng (embedded)...

    Cảm giác nó hiểu lời nhắc hơn á, tại vì mình thử nhiều mô hình ít tham số mà nó hay lơ đi lời nhắc của mình. Ví dụ bảo: "Chỉ trả về câu trả lời, không cần giải thích gì thêm" thì rất nhiều cái vẫn cứ phải chêm vào câu mở đầu, giải thích... còn với gemma-3n thì trả lời rất đúng trọng tâm.

    » Xem thêm
  • Trước là sử dụng CSS để tạo hiệu ứng "loading", còn giờ có thể chỉ cần mỗi 1 tệp svg cũng "loading" được luôn: svg-loaders

    » Xem thêm

Vấn đề

Trong quá trình phát triển hoặc vận hành hệ thống phần mềm, có những lúc phát sinh ra nhiều vấn đề mà chúng ta không lường trước được. Một khi ứng dụng được tung ra thị trường, lượng người dùng tăng theo từng ngày tạo ra sự đa dạng về hành vi lẫn dữ liệu sinh ra trong hệ thống. Chúng kết hợp với nhau để bùng nổ những lỗi mà quá trình kiểm thử trước đó không hề biết.

Một trong số đó có thể kể đến là tốc độ phản hồi API bỗng trở nên chậm chạp mặc dù lượng người sử dụng là không nhiều. Khi kiểm tra, có vẻ bạn phát hiện ra hoặc nghi ngờ một hàm nào đó mất thời gian xử lý. Để cho chắc chắn thì tất nhiên phải làm cách nào đó để đo xem hàm đó tốn bao nhiêu thời gian xử lý. Có nhiều cách để tìm xem hàm nào đang tiêu tốn thời gian. Nhiều ứng dụng APM có khả năng kiểm soát và chuẩn đoán hiệu suất ứng dụng rất tốt, kịp thời cảnh báo vấn đề đến người quản trị. Một vài dịch vụ APM còn có tính năng thu thập hoặc cảnh báo theo thời gian thực nếu như chúng phát hiện ra một hàm nào đó đang mất quá nhiều thời gian để xử lý. Hay chí ít là cảnh báo thời gian phản hồi quá lâu. Nhưng đổi lại giá thành của chúng không hề rẻ, nếu có miễn phí thì nhiều hạn chế kèm theo buộc phải nâng cấp nếu muốn dùng thoải mái. Vì lẽ đó không phải ai cũng có điều kiện sử dụng APM, đó là lúc bạn cần đến một cách "xôi thịt" hơn nhưng lại hoàn toàn miễn phí, ai cũng có thể tiếp cận được.

Đo lường thời gian thực hiện hàm trong Javascript

Date.now(), console.time(), performance.now(), process.hrtime()... là các hàm thường được dùng để đo khoảng thời gian thực hiện lệnh. Về cơ bản, chỉ cần kẹp giữa hàm cần đo thì sẽ tính được thời gian thực thi.

Ví dụ dùng Date để tính thời gian thực thi của hàm functionToBeMeasured giống như sau:

const start = Date.now();

await functionToBeMeasured();

const end = Date.now();
console.log(`Execution time: ${end - start} ms`);

Cũng có thể làm tương tự với console.time:

console.time('executionFunctionToBeMeasured');

await functionToBeMeasured();

console.timeEnd('executionFunctionToBeMeasured');

Tuy vậy, nếu muốn độ chính xác theo phần nghìn giây, hãy sử dụng hàm mạnh mẽ hơn với performance.now() trong trình duyệt hoặc process.hrtime() nếu sử dụng Node.js.

const start = performance.now();

await functionToBeMeasured();

const end = performance.now();
console.log(`Execution time: ${end - start} ms`);

Sau khi biết nguyên lý đo thời gian, vấn đề là làm cách nào để dùng. Chẳng lẽ cứ phải tìm và kẹp giữa hàm bằng 2 dòng startend? Tin vui là không cần phải làm thế. Ý tưởng lúc này là viết một hàm gói gọn hàm khác để đo thời gian. Hàm này có đầu vào là một hàm cần đo thời gian, đầu ra là kết quả của hàm đó kèm với thời gian thực thi. Một cái gì đó trông giống như dưới đây:

calcExecuteTime(functionToBeMeasured);

Với calcExecuteTime làm hàm cần tạo ra. functionToBeMeasured là hàm cần do thời gian. Đôi khi functionToBeMeasured có cả tham số, vì thế hãy sửa lại một chút.

calcExecuteTime(() => functionToBeMeasured(arg1, arg2...));

Nếu trong functionToBeMeasured có sử dụng this, hãy thêm một tham số ngữ cảnh để nhận this từ nơi gọi hàm, đảm bảo ngữ cảnh cho hàm.

calcExecuteTime(context, () => functionToBeMeasured(arg1, arg2...));

Cuối cùng, nên thêm một tham số name để xác định được cuộc gọi hàm từ đâu.

calcExecuteTime(name, context, () => functionToBeMeasured(arg1, arg2...));

Tổng hợp lại, hàm calcExecuteTime có thể giống như sau:

const calcExecuteTime = async (name, context, fn) => {
  const start = process.hrtime();
  const result = await fn.call(context);
  const stop = process.hrtime(start);
  const executeTime = (stop[0] * 1e9 + stop[1]) / 1e9;
  console.log(`${name} execution time: ${executeTime}s`);
  return result;
};

Bây giờ hãy thử gọi hàm xem:

calcExecuteTime("Execute ToBeMeasured", this, () => functionToBeMeasured(arg1, arg2...));
// Execute ToBeMeasured execution time: 0.000178s

Bạn có thể sửa lại hàm tuỳ thích, ví dụ thay vì console.log thì ghi lại thời gian thực hiện hàm vào đâu đó, ví dụ như một tệp .log hoặc bắn lên dịch vụ đám mây nào đó. Ngoài ra có thể thêm một cờ bật/tắt tính năng tính năng đo thời gian khi nó không cần thiết nữa.

Tham khảo:

Cao cấp
Hello

5 bài học sâu sắc

Mỗi sản phẩm đi kèm với những câu chuyện. Thành công của người khác là nguồn cảm hứng cho nhiều người theo sau. 5 bài học rút ra được đã thay đổi con người tôi mãi mãi. Còn bạn? Hãy bấm vào ngay!

Mỗi sản phẩm đi kèm với những câu chuyện. Thành công của người khác là nguồn cảm hứng cho nhiều người theo sau. 5 bài học rút ra được đã thay đổi con người tôi mãi mãi. Còn bạn? Hãy bấm vào ngay!

Xem tất cả

Đăng ký nhận thông báo bài viết mới

hoặc
* Bản tin tổng hợp được gửi mỗi 1-2 tuần, huỷ bất cứ lúc nào.

Bình luận (1)

Nội dung bình luận...
Avatar
Tuan Nguyen2 năm trước

Thử chạy cái hàm đó trong 1_000_000 rồi tính trung bình sau đó đem so với chạy cái hàm đó 1 lần. Kết quả sẽ bất ngờ đó. Đó là cơ chế của node

Trả lời
Avatar
Xuân Hoài Tống2 năm trước

Bạn ơi đó là cơ chế gì vậy ạ?