Đ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
  • Mọi người đã nghe nói đến Jujutsu - jj - một dạng quản lý phiên bản cho mã nguồn (version control system) chưa? Có vẻ như nó đang nhận được nhiều sự quan tâm.

    Chờ xíu! Chẳng phải git đã quá tốt rồi sao? Thế thì chế ra thằng jj để làm gì nữa? Cũng hơi khó trả lời nhỉ? Mỗi công cụ sinh ra chắc chắn phải cải thiện hoặc khắc phục được nhược điểm của cái trước. Cho nên jj ắt hẳn phải làm được điều gì đó mà git chưa làm được nên mới nổi lên như vậy.

    Thật ra mình đã nghe nói đến jj từ vài tháng trước rồi, nhưng vào đọc thì toàn kiến thức cao siêu. Hoặc là đang mang nặng cái lối suy nghĩ của git vào trong đầu rồi nên chưa lĩnh hội ra được điều gì cả.

    Mình hay có kiểu cái gì đọc lần 1 mà không hiểu thì đọc tiếp lần 2, lần 2 không hiểu thì đọc tiếp lần 3... đến lần thứ n mà vẫn không hiểu thì bỏ. Cơ mà không phải là từ bỏ mà một thời gian sau đó quay lại đọc tiếp. Đến một lúc nào đó khả năng mình sẽ hiểu ra một ít vấn đề, thế mới tài 😆.

    Thì cái jj này có vẻ như nó đang mở ra được tính linh hoạt trong việc "cam kết" mã. Tưởng tượng bạn đang làm việc trên một dự án, đang ở nhánh này, muốn sang nhánh khác để sửa, nhưng mà lại đang viết dở ở nhánh này, thế là phải stash, rồi checkout, rồi commit, rồi merge hoặc rebase lại vào nhánh cũ... nhìn chung quá trình làm việc với git nghiêm ngặt đến mức cứng nhắc, cần nhiều thao tác để giải quyết một vấn đề, chưa kể cái cây commit (commit-tree) nữa thì ôi thôi, khỏi xem cho đỡ nhức mắt. Thế nên ông jj này đang làm cách nào đó để bạn khỏi cần phải quan tâm đến các nhánh luôn, sửa trực tiếp vào commit. Nghe ảo nhỉ 😂.

    Đấy mới lĩnh hội được đến đấy, hy vọng sau n lần đọc lại nữa mình sẽ viết được một bài chi tiết hơn về công cụ này.

    » Xem thêm
  • Gòi gòi tới công chiện gòi 🤤🤤🤤

    » Xem thêm
  • Không biết blog được dẫn nguồn từ trang cà phê nào hay sao mà vài ba hôm trở lại đây thấy nhiều người tìm kiếm cà phê thế không biết 🤔.

    Tìm cả cách pha với tìm cả loại hạt, khổ nỗi họ tìm lại không ra bài viết nào vì mình chưa có viết đến mấy trường hợp đó. Phải chăng là ý trời 😀🙏

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

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 ạ?
Bấm hoặc cuộn mạnh để sang bài mới