Measuring the Execution Time of Functions in JavaScript in a Graceful Way

Measuring the Execution Time of Functions in JavaScript in a Graceful Way

Daily short news for you
  • For a long time, I have been thinking about how to increase brand presence, as well as users for the blog. After much contemplation, it seems the only way is to share on social media or hope they seek it out, until...

    Wearing this shirt means no more worries about traffic jams, the more crowded it gets, the more fun it is because hundreds of eyes are watching 🤓

    (It really works, you know 🤭)

    » Read more
  • A cycle of developing many projects is quite interesting. Summarized in 3 steps: See something complex -> Simplify it -> Add features until it becomes complex again... -> Back to a new loop.

    Why is that? Let me give you 2 examples to illustrate.

    Markdown was created with the aim of producing a plain text format that is "easy to write, easy to read, and easy to convert into something like HTML." At that time, no one had the patience to sit and write while also adding formatting for how the text displayed on the web. Yet now, people are "stuffing" or creating variations based on markdown to add so many new formats that… they can’t even remember all the syntax.

    React is also an example. Since the time of PHP, there has been a desire to create something that clearly separates the user interface from the core logic processing of applications into two distinct parts for better readability and writing. The result is that UI/UX libraries have developed very robustly, providing excellent user interaction, while the application logic resides on a separate server. The duo of Front-end and Back-end emerged from this, with the indispensable REST API waiter. Yet now, React doesn’t look much different from PHP, leading to Vue, Svelte... all converging back to a single point.

    However, the loop is not bad; on the contrary, this loop is more about evolution than "regression." Sometimes, it creates something good from something old, and people rely on that goodness to continue the loop. In other words, it’s about distilling the essence little by little 😁

    » Read more
  • Alongside the official projects, I occasionally see "side" projects aimed at optimizing or improving the language in some aspects. For example, nature-lang/nature is a project focused on enhancing Go, introducing some changes to make using Go more user-friendly.

    Looking back, it resembles JavaScript quite a bit 😆

    » Read more

The Issue

During the development or operation of software systems, there are times when many unforeseen issues arise. Once the application is launched to the market, the number of users increases daily, creating a diversity of behaviors and data generated within the system. These combine to explode bugs that the previous testing process was unaware of.

One of these can be the API response speed suddenly becoming sluggish, even though the number of users is not high. When checking, it seems you discover or suspect that a certain function is taking too long to process. To be sure, you must find a way to measure how much processing time that function costs. There are many ways to find out which function is consuming time. Many APM applications have excellent capabilities to monitor and diagnose application performance, promptly alerting issues to administrators. Some APM services even have real-time monitoring or alerting features if they detect that a function is taking too much time to process. Or at least alerting about overly long response times. However, the cost of these services is not cheap; if free, there are many limitations that require upgrading for comfortable use. Therefore, not everyone can afford to use APM, which is when you need a more "down-to-earth" method that is completely free and accessible to everyone.

Measuring Function Execution Time in JavaScript

Date.now(), console.time(), performance.now(), process.hrtime()... are commonly used functions to measure the execution time of commands. Basically, you just need to wrap the function you want to measure to calculate its execution time.

For example, using Date to calculate the execution time of the functionToBeMeasured function as follows:

const start = Date.now();

await functionToBeMeasured();

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

You can also do similarly with console.time:

console.time('executionFunctionToBeMeasured');

await functionToBeMeasured();

console.timeEnd('executionFunctionToBeMeasured');

However, if you want accuracy to the millisecond, use a more powerful function with performance.now() in the browser or process.hrtime() if using Node.js.

const start = performance.now();

await functionToBeMeasured();

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

Once you understand the principle of measuring time, the question is how to use it. Should you keep finding and wrapping functions with 2 lines of start and end? The good news is you don't have to do that. The idea now is to write a function that encapsulates another function to measure the time. This function takes as input a function that needs to measure time, and its output is the result of that function along with the execution time. Something that looks like this:

calcExecuteTime(functionToBeMeasured);

With calcExecuteTime being the function to create. functionToBeMeasured is the function you want to measure time for. Sometimes functionToBeMeasured has parameters, so let's adjust a bit.

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

If functionToBeMeasured uses this, add a context parameter to receive this from where the function is called, ensuring the context for the function.

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

Finally, you should add a name parameter to identify where the function call comes from.

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

In summary, the calcExecuteTime function could look like this:

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;
};

Now let's try calling the function:

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

You can modify the function as you like, for example, instead of console.log, log the execution time somewhere, such as a .log file or send it to a cloud service. Additionally, you can add a flag to enable/disable the timing feature when it is no longer necessary.

References:

Premium
Hello

5 profound lessons

Every product comes with stories. The success of others is an inspiration for many to follow. 5 lessons learned have changed me forever. How about you? Click now!

Every product comes with stories. The success of others is an inspiration for many to follow. 5 lessons learned have changed me forever. How about you? Click now!

View all

Subscribe to receive new article notifications

or
* The summary newsletter is sent every 1-2 weeks, cancel anytime.

Comments (1)

Leave a comment...
Avatar
Tuan Nguyen2 years ago

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

Reply
Avatar
Xuân Hoài Tống2 years ago

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