Đ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

Những mẩu tin ngắn hàng ngày dành cho bạn
  • Có một nghiên cứu khá thú vị mà mình rút ra được đó là: "Người dùng chẳng bao giờ chịu đọc những thứ mà họ không muốn". (Khẳng định chắc nịch thế chứ, đa số thì đúng hơn 😅).

    Không tin á, mình dám cá chắc là bạn đã không ít lần gặp trường hợp nhấn vào một nút gì đó liên tục mà nó không phản hồi, nhưng thật ra là nó có báo một dòng lỗi ở đâu đó. Hoặc nhập xong xuôi các thứ rồi đến lúc nhấn nút gửi thì không gửi được. Bực mình mới kéo lên trên hoặc xuống dưới đọc thì à... hoá ra là phải làm thêm bước này bước kia đúng không?

    Cũng chẳng đâu xa ngay như blog của mình đây. Nghĩ là mọi người ai mà quan tâm đến blog sẽ nhấn vào nút "Cho phép bật thông báo" ở ngay phía dưới bài viết. Nhưng sự thật là chẳng ai thèm bấm cả. Có phải là họ không muốn nhận không? Chắc là không! Mình nghĩ do họ không đọc đến dòng đó thôi.

    Bằng chứng là chỉ khi cho hiện một thông báo chiếm một nửa cái màn hình, hoặc bất ngờ hiện ra để gây sự chú ý thì họ mới thật sự đọc và dĩ nhiên thu hút thêm vài người đăng ký - điều mà trước đó chẳng bao giờ đạt được.

    » Xem thêm
  • Một bài viết về các khái niệm Functors, Applicatives và Monads trong lập trình hàm mà cứ mỗi lần đọc thì lại hiểu ra được một ít 😅

    Functors, Applicatives, And Monads In Pictures

    » Xem thêm
  • Rust kiểu thời tới thời tới... Nó đang "tái định nghĩa" lại một đống thứ. Kể cả bộ coreutils chứa các câu lệnh Linux cơ bản cũng đã được hắn ta viết lại, còn chạy được trên đa nền tảng nữa chứ 🫣

    uutils.github.io

    » Xem thêm

Vấn đề

Trong quá trình phát triển ứng dụng hoặc đang vận hành nó trong môi trường production sẽ có lúc phát sinh ra nhiều vấn đề mà chúng ta không lường trước được. Khi ứng dụng được tung ra thị trường, chắc chắn lượng người dùng sẽ nhiều lên từng ngày, từ đó tạo ra sự đa dạng về hành vi lẫn dữ liệu người dùng thu thập được. Chúng kết hợp với nhau tạo ra nhiều trường hợp phát sinh lỗi mà quá trình kiểm thử trước đó không hề phát hiện ra.

Một trong số đó có thể kể đến như 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 lại tính năng gây ra tình trạng đó, có vẻ bạn phát hiện ra hoặc đang nghi ngờ một hàm nào đó chiếm lượng thời gian xử lý lớn. Để chắc chắn là mình đúng thì tất nhiên phải đo được xem cụ thể là hàm đó tốn bao nhiêu thời gian để xử lý.

Có nhiều cách để biết hàm nào đang gây chậm hệ thống. Các ứng dụng APM với khả năng kiểm soát và chuẩn đoán ứng dụng của bạn rất tốt để kịp thời cảnh báo vấn đề. Một vài dịch vụ APM 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 để thực hiện, hoặc thời gian phản hồi của API là quá lâu. Nhưng đổi lại, giá thành của chúng không hề rẻ, hoặc nếu có miễn phí thì nhiều hạn chế sẽ phát sinh. 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í mà 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 hay được sử dụng để đo khoảng thời gian mà hàm thực hiện. Về cơ bản, chỉ cần kẹp giữa hàm cần đo bằng chúng thì sẽ tính được thời gian thực thi.

Ví dụ sau dử dụng Date để tính thời gian thực thi bằng cách trừ hai khoảng thời gian trước và sau khi hàm được chạy.

const start = Date.now();

await functionToBeMeasured();

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

Ngoài ra, đơn giản hơn thì dùng console.time:

console.time('executionFunctionToBeMeasured');

await functionToBeMeasured();

console.timeEnd('executionFunctionToBeMeasured');

console.time không mang lại độ chính xác cao. 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() 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 cách đo thời gian, một vấn đề khác nảy sinh đó chính là cần phải đặt hàm cần đo kẹp giữa hai hàm tính thời gian. Điều này gây ra sự xáo trộn mã trong dự án của bạn, phải sửa nhiều hơn, mã trở nên cồng kềnh hơn và khó kiểm soát.

Ý tưởng lúc này là viết một hàm để gói gọn tính năng đo thời gian thực thi. Đầu vào là một hàm cần tính còn đầu ra là kết quả của hàm đó cùng với thời gian thực thi. Một hàm gì đó trông giống như dưới đây:

calcExecuteTime(functionToBeMeasured);

functionToBeMeasured đôi khi là hàm 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ố context để nhận this từ nơi gọi.

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...));

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ũng có thể sửa lại hàm tùy vào mục đích, ví dụ thay vì console.log thì hãy logging lại thời gian thực hiện hàm vào đâu đó. Hoặc nâng cấp hàm lên ví dụ như thêm một cờ bật/tắt tính năng tính thời gian.

Tham khảo:

Cao cấp
Hello

Bí mật ngăn xếp của Blog

Là một lập trình viên, bạn có tò mò về bí mật công nghệ hay những khoản nợ kỹ thuật về trang blog này? Tất cả bí mật sẽ được bật mí ngay bài viết dưới đây. Còn chờ đợi gì nữa, hãy bấm vào ngay!

Là một lập trình viên, bạn có tò mò về bí mật công nghệ hay những khoản nợ kỹ thuật về trang blog này? Tất cả bí mật sẽ được bật mí ngay bài viết dưới đây. Còn chờ đợi gì nữa, 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.
Author

Xin chào, tôi tên là Hoài - một anh Dev kể chuyện bằng cách viết ✍️ và làm sản phẩm 🚀. Với nhiều năm kinh nghiệm lập trình, tôi đã đóng góp một phần công sức cho nhiều sản phẩm mang lại giá trị cho người dùng tại nơi đang làm việc, cũng như cho chính bản thân. Sở thích của tôi là đọc, viết, nghiên cứu... Tôi tạo ra trang Blog này với sứ mệnh mang đến những bài viết chất lượng cho độc giả của 2coffee.dev.Hãy theo dõi tôi qua các kênh LinkedIn, Facebook, Instagram, Telegram.

Bạn thấy bài viết này có ích?
Không

Bình luận (1)

Nội dung bình luận...
Avatar
Tuan Nguyen1 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ống1 năm trước
Bạn ơi đó là cơ chế gì vậy ạ?