Đ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
  • Từ lâu rồi suy nghĩ làm thế nào để tăng sự hiện diện thương hiệu, cũng như người dùng cho blog. Nghĩ đi nghĩ lại thì chỉ có cách chia sẻ lên mạng xã hội hoặc trông chờ họ tìm kiếm, cho đến khi...

    In cái áo này được cái tắc đường khỏi phải lăn tăn, càng đông càng vui vì hàng trăm con mắt nhìn thấy cơ mà 🤓

    (Có tác dụng thật nha 🤭)

    » Xem thêm
  • Một vòng của sự phát triển nhiều dự án khá là thú vị. Tóm tắt lại trong 3 bước: Thấy một cái gì đó phức tạp -> Làm cho nó đơn giản đi -> Thêm thắt tính năng cho đến khi nó phức tạp... -> Quay trở lại vòng lặp mới.

    Tại sao lại như vậy? Để mình lấy 2 ví dụ cho các bạn thấy.

    Markdown ra đời với mục tiêu tạo ra một định dạng văn bản thô "dễ viết, dễ đọc, dễ dàng chuyển thành một dạng gì đó như HTML". Vì thời đó chẳng ai đủ kiên nhẫn mà vừa ngồi viết vừa thêm định dạng cho văn bản hiển thị ở trên web như thế nào. Ấy vậy mà giờ đây người ta đang "nhồi nhét" hoặc tạo ra các biến thể dựa trên markdown để bổ sung thêm nhiều định dạng mới đến mức... chẳng nhớ nổi hết cú pháp.

    React cũng là một ví dụ. Từ thời PHP, việc khát khao tạo ra một cái gì đó tách biệt hẳn giao diện người dùng và phần xử lý logic chính của ứng dụng thành 2 phần riêng biệt cho dễ đọc, dễ viết. Kết quả là các thư viện UI/UX phát triển rất mạnh mẽ, mang lại khả năng tương tác với người dùng rất tốt, còn phần logic ứng dụng thì nằm ở một máy chủ riêng biệt. Bộ đôi Front-end, Back-end cũng từ đấy mà thịnh hành, không thể thiếu anh bồi bàn REST API. Ấy vậy mà giờ đây React trông cũng không khác biệt gì so với PHP là mấy, kéo theo là cả Vue, Svelte... lại cùng quy tất cả về một mối.

    Cơ mà không phải vòng lặp là xấu, ngược lại vòng lặp này mang tính tiến hoá nhiều hơn là "cải lùi". Nhiều khi lại tạo ra được cái hay hơi cái cũ thế là người ta lại dựa trên cái hay đó để tiếp tục lặp. Nói cách khác là chắc lọc tinh hoa từng tí một tí một á 😁

    » Xem thêm
  • Song song với các dự án chính thức thì thi thoảng mình vẫn thấy các dự án "bên lề" nhằm tối ưu hoặc cải tiến ngôn ngữ theo khía cạnh nào đó. Ví dụ nature-lang/nature là một dự án hướng tới cải tiến Go, mang lại một số thay đổi nhằm giúp cho việc sử dụng Go trở nên thân thiện hơn.

    Nhìn lại mới thấy hao hao JavaScript 😆

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