Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to measure the execution time of an asynchronous function in nodejs?

I'm trying to get the execution/response time of an asynchronous function that executes inside a node-fetch operation, like the following

async function getEditedData() {      
       var a = await fetch(`https://api.example.com/resorce_example`);
       var b = await a.json();
       // Some aditional treatment of the object obtained (b)
       console.log("End of the asynchronous function")
}

I Used the library perf_hooks like this, but the execution time shows before

const hrtime = require ('perf_hooks').performance.now ;
var start = hrtime ();
   getEditedData();
var end   = hrtime ();
console.log (end - start);

I found the async_hooks library https://nodejs.org/api/perf_hooks.html#perf_hooks_measuring_the_duration_of_async_operations , but I can´t understand how it works. I am a basic in javascript/nodejs

like image 582
Kev Rodríguezz Avatar asked Apr 03 '20 19:04

Kev Rodríguezz


People also ask

How would you measure the performance of async operations?

In async-await you get the performance boost because your app can do the same with less threads, or do more with the same threads. To measure that you need to have a lot of async operations concurrently. Only then will you notice that the async option utilizes CPU resources better than the synchronous one.


3 Answers

You could simply store Date.now() in some variable and then check Date.now() when your Promise resolves (or rejects) and subtract to find the difference. For example:

const simulateSomeAsyncFunction = new Promise((resolve, reject) => {
  console.log('Initiating some async process, please wait...')
  const startTime = Date.now();

  setTimeout(() => {
    resolve(Date.now() - startTime);
  }, 3000);
});

simulateSomeAsyncFunction.then(msElapsed => {
  console.log(`Async function took ${msElapsed / 1000} seconds to complete.`);
});

Note: You could write code that achieves the same thing and appears to be synchronous by using await/async since that is just "syntactic sugar" built on top of Promises. For example:

const simulateSomeAsyncFunction = () => {
  console.log('Initiating some async process, please wait...');

  return new Promise((resolve, reject) => {
    setTimeout(resolve, 3000);
  });
};

// Await is required to be called within an async function so we have to wrap the calling code in an async IIFE
(async() => {
  const startTime = Date.now();

  await simulateSomeAsyncFunction();

  const msElapsed = Date.now() - startTime;

  console.log(`Async function took ${msElapsed / 1000} seconds to complete.`);
})();
like image 130
Tom O. Avatar answered Sep 18 '22 22:09

Tom O.


Starting with a simple async function -

const fakeAsync = async (value) => {
  const delay = 2000 + Math.random() * 3000 // 2 - 5 seconds
  return new Promise(r => setTimeout(r, delay, value))
}

fakeAsync("foo").then(console.log)

console.log("please wait...")

// "please wait..."
// "foo"

We could write a generic function, timeit. This is a higher-order function that accepts a function as input and returns a new function as output. The new function operates like a decorated version of the original -

const timeit = (func = identity) => async (...args) => {
  const t = Date.now()
  const result = await func(...args)
  return { duration: Date.now() - t, result }
}

// decorate the original
const timedFakeAsync = timeit(fakeAsync)

// call the decorated function
timedFakeAsync("hello").then(console.log)
timedFakeAsync("earth").then(console.log)

// { duration: 3614, result: "earth" }
// { duration: 4757, result: "hello" }

The timed version of our function returns an object, { duration, result }, that reports the runtime of our async function and the result.

Expand the snippet below to verify the results in your own browser -

const identity = x =>
  x

const timeit = (func = identity) => async (...args) => {
  const t = Date.now()
  const result = await func(...args)
  return { duration: Date.now() - t, result }
}

const fakeAsync = async (value) => {
  const delay = 2000 + Math.random() * 3000 // 2 - 5 seconds
  return new Promise(r => setTimeout(r, delay, value))
}

const timedFakeAsync = timeit(fakeAsync)

timedFakeAsync("hello").then(console.log)
timedFakeAsync("earth").then(console.log)

console.log("please wait...")

// "please wait..."
// { duration: 3614, result: "earth" }
// { duration: 4757, result: "hello" }
like image 36
Mulan Avatar answered Sep 17 '22 22:09

Mulan


If you expect to set the end after getEditedData() is completed, you actually need to await getEditedData(). Otherwise, you'll go right past it while it executes... asynchrnously.

like image 40
Brad Avatar answered Sep 20 '22 22:09

Brad