Check performance of async and sync functions in JavaScript

Learn how to check the performance of an async and sync functions in Javascript.

This question was asked in Atlassian’s frontend interview and if you are preparing for frontend interviews then checkout alpha.learnersbucket.com

To check the performance of the function or any code that runs in Javascript, we basically check how much time it took for the execution and we do that by using performance.now() method that returns the current timestamp.

We will create an async function measurePeformance() that will take the function as input whose performance has to be evaluated and other props like:

  • name – The name of the function or the default alias for the anonymous functions.
  • iterations – Number of time the function should be invoked, helps to get the average computation time with high and low time.
  • warmup – This flag will be used to run the function once to make sure it is not throwing any error before starting the performance test.
  • logResults – This flag will be used to determine if we have to log the results or not.
async function measurePerformance(fn, options = {}) {
  const {
    name = fn.name || 'Anonymous Function',
    iterations = 1,
    warmup = true,
    logResults = true
  } = options;

  const results = {
    name,
    iterations,
    isAsync: fn.constructor.name === 'AsyncFunction',
    timings: [],
    average: 0,
    min: Infinity,
    max: -Infinity,
    total: 0
  };

  // if warmup enabled
  if (warmup) {
    try {
      await fn();
    } catch (error) {
      console.warn(`Warmup run failed for ${name}:`, error);
    }
  }

  // execute the function for the defined iterations
  for (let i = 0; i < iterations; i++) {
    const start = performance.now();
    try {
      await fn();
    } catch (error) {
      console.error(`Error in iteration ${i + 1} for ${name}:`, error);
      continue;
    }
    const end = performance.now();
    const duration = end - start;
    
    // compute and store the results
    results.timings.push(duration);
    results.min = Math.min(results.min, duration);
    results.max = Math.max(results.max, duration);
    results.total += duration;
  }

  // calculate averages
  results.average = results.total / results.timings.length;

  // log results
  if (logResults) {
    console.log(`\nPerformance Results for ${name}:`);
    console.log('----------------------------------------');
    console.log(`Type: ${results.isAsync ? 'Async' : 'Sync'}`);
    console.log(`Iterations: ${iterations}`);
    console.log(`Average: ${results.average.toFixed(2)}ms`);
    console.log(`Min: ${results.min.toFixed(2)}ms`);
    console.log(`Max: ${results.max.toFixed(2)}ms`);
    console.log('----------------------------------------\n');
  }

  return results;
}

Testcase: Normal function

Input:
// normal function
const syncFunction = () => {
  let sum = 0;
  for (let i = 0; i < 1000000; i++) {
    sum += i;
  }
  return sum;
};

// measure performance of the normal function
measurePerformance(syncFunction, {
  name: 'Sync Calculation',
  iterations: 5,
  warmup: true
});

Output:
"Performance Results for Sync Calculation:"
"----------------------------------------"
"Type: Sync"
"Iterations: 5"
"Average: 10.00ms"
"Min: 9.00ms"
"Max: 11.00ms"
"----------------------------------------"

Testcase: Async function

Input:
// async function
const asyncFunction = async () => {
  await new Promise(resolve => setTimeout(resolve, 100));
  return 'done';
};

// measure performance of the async function
measurePerformance(asyncFunction, {
  name: 'Async Calculation',
  iterations: 5,
  warmup: true
});

Output:
"Performance Results for Async Calculation:"
"----------------------------------------"
"Type: Async"
"Iterations: 5"
"Average: 105.60ms"
"Min: 104.00ms"
"Max: 107.00ms"
"----------------------------------------"

Compare performance of two or more functions in JavaScript

We can reuse the measurePerformance function and create a comparePerformance function that will take two or more functions and compare there performance.

async function comparePerformance(functions, options = {}) {
  const { logResults } = options;
  const results = [];
  
  for (const { fn, name } of functions) {
    const result = await measurePerformance(fn, { ...options, name });
    results.push(result);
  }

  // sort results by average time
  results.sort((a, b) => a.average - b.average);

  if (logResults !== false) {
    console.log('\nPerformance Comparison:');
    console.log('----------------------------------------');
    results.forEach((result, index) => {
      console.log(`${index + 1}. ${result.name}:`);
      console.log(`   Average: ${result.average.toFixed(2)}ms`);
      console.log(`   Min: ${result.min.toFixed(2)}ms`);
      console.log(`   Max: ${result.max.toFixed(2)}ms`);
    });
    console.log('----------------------------------------\n');
  }

  return results;
}

Testcase

Input:
// async function
const asyncFunction = async () => {
  await new Promise(resolve => setTimeout(resolve, 100));
  return 'done';
};

// normal function
const syncFunction = () => {
  let sum = 0;
  for (let i = 0; i < 1000000; i++) {
    sum += i;
  }
  return sum;
};

// compare two functions
await comparePerformance([
  { fn: syncFunction, name: 'Sync Calculation' },
  { fn: asyncFunction, name: 'Async Operation' }
], {
  iterations: 5,
  warmup: true
});

Output:
"Performance Results for Sync Calculation:"
"----------------------------------------"
"Type: Sync"
"Iterations: 5"
"Average: 2.40ms"
"Min: 2.00ms"
"Max: 3.00ms"
"----------------------------------------"

"Performance Results for Async Operation:"
"----------------------------------------"
"Type: Async"
"Iterations: 5"
"Average: 104.40ms"
"Min: 100.00ms"
"Max: 113.00ms"
"----------------------------------------"

"Performance Comparison:"
"----------------------------------------"
"1. Sync Calculation:"
"   Average: 2.40ms"
"   Min: 2.00ms"
"   Max: 3.00ms"

"2. Async Operation:"
"   Average: 104.40ms"
"   Min: 100.00ms"
"   Max: 113.00ms"
"----------------------------------------"