Đ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

Threads
  • Có bạn nào trong lúc code mà bị "ngẫn tò te" hoặc "lú lẫn" trong mớ hỗn độn của mình viết ra chưa. Những lúc như thế tôi thường hay ngừng lại, thư giãn đầu óc, hoặc để mai tính tiếp. Ấy vậy mà rất hiệu quả nhé! Lúc sau xem lại cái tự nhiên thấy vấn đề ở đâu ngay.

    Hoặc cũng có thể thử áp dụng phương pháp "chú vịt vàng" - thử giải thích vấn đề đang gặp phải với vịt xem, nó sẽ cho thấy mâu thuẫn trong lời nói ra.

    Còn không có tiền mua vịt to thì xe túi mù ra vịt bé giống mình nè 😅

    » Xem thêm
  • Ơ buồn cười thật. Ai cũng biết GIF là định dạng ảnh động thường được dùng thay cho video clip để hiển thị các nội dung ngắn trên nền tảng web. GIF tiện hơn các nội dung dạng video là vì nó được hiển thị như một bức ảnh và được hỗ trợ rộng rãi. Cơ mà GIF có dung lượng nặng quá.

    Nói thật nhiều lúc mình có vài cái hành động muốn hiển thị lên web cho mọi người xem, cơ mà định dạng GIF nó nặng với cả cũng không biết cách tối ưu cho nhẹ xuống. Hôm nay lên mạng tìm hiểu xem định dạng nào có khả năng thay thế GIF trong tương lai thì mọi người biết đó là gì không? Là WEBP (webp)!!! Đúng vậy, là định dạng ảnh mà mình đang dùng trên blog lâu nay luôn á, mà giờ mới biết là nó hiển thị được cả ảnh động nữa, hơi quê 😆

    Kết hợp với ffmpeg nữa là chuyển được tất tần tật video clip thành webp được ngay. Để vài nửa ngồi chế lại cái cli một tí là dùng ngon luôn mọi người ạ 🤪

    » Xem thêm
  • Cảm giác như Github Copilot đang cố gắng mở rộng thị trường cho anh em developer á. Mới trước họ ra mắt Github Open Copilot Chat thì mới đây lại thêm cái Using GitHub Copilot in the command line dùng để giải thích hoặc gợi ý lệnh trong terminal.

    Đây, cách dùng rất đơn giản thôi, ví dụ muốn nó giải thích câu lệnh sudo apt-get để làm gì, thì:

    $ gh copilot explain "sudo apt-get"

    Hoặc nhờ nó gợi ý lệnh mong muốn, sử dụng tiếng Việt được luôn nhé (kể cả tiếng Việt không dấu vẫn hiểu 😳)

    $ gh copilot suggest "xoá commit chưa push"

    Mình đã kiểm tra và thấy lệnh ra rất đúng, xịn thật 🤓

    » 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:

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 ạ?