console.log() VS return statement

console.log() VS return statement

What kind of comparison is this

I know comparisons should be done between two functions if they complete the same task but in two different ways. But hear me out for a second. Imagine, for some reason, you need to do many console.log()s on the production release of your app. Or maybe you forgot to remove that console.log("is this working?") inside a loop that may run so many times. Can you guess how much impact it'll have on your app compared to a return statement?

How much?

Don't be so lazy. Come on, guess something. Give me a number. How much slower/faster console.log() will be compared to the return statement? Okay, I'll give you a hint. It's slower. But how much? 2 times? 3 times? 4 times?

In a test case, I found console.log() is around 300x SLOWER than return. Yes. THREE FACKING HUNDRED
Cannot believe that? Check the below screenshot

I know it's only for a single run. Wanna guess what the number will be for 10 runs?
Check below...

The number drastically dropped, right? Like from nearly 300 to directly 61. Yeah, I give you that. Maybe it'll drop to around 6-7 for 100 runs? RIGHT? Not really...

This time we got around 40. Not a big drop like the last one, and also not a small number, when we talk about completion time.

The Table

As we have come so long, let's look at some more numbers in a more structured way. Maybe a table.

RunsSlower
1299x
1061.1x
10039.74x
100042.475x
1000063.2221x
10000057.96388x
100000056.139433x

Do you see something? Even for the highest number of runs, console.log() is still around 55x slower then return.

The Code

Now the biggest question is, where did I get this number? Well, I wrote a simple script to benchmark these two statements. In case you wanna check those, here it is

function logIt(string: string): void {
  console.log(string);
}

function returnIt(string: string): string {
  return string;
}

In the above script, I made two simple functions. One is for logging out a string and another one just returns a string.

function performanceCheck(func: Function, name?: string) {
  return function (...arg: any[]) {
    const start = performance.now();
    func(...arg);
    const end = performance.now();

    const takenTime = end - start;

    /*
       Uncomment the below line to check
       which function took how much time
    */
    // console.log(`${name} took: ${takenTime}ms`);

    return takenTime;
  };
}

Then I wrote the above performanceCheck function that takes two arguments. The first argument is the actual function that we'll run, and the second optional argument is the name of the function, that we can use to check which function took how much time to complete, by measuring the before and after values of performance.now()
We can use this performanceCheck function to easily run our main two functions logIt and returnIt. Below is the use case

function runningTheTest(times: number) {
  const resultArray: number[] = [];

  const text = "  logging it";
  for (let _i = 0; _i < times; _i++) {
    const performanceParam_log = performanceCheck(logIt, "console.log()");
    const performanceParam_return = performanceCheck(returnIt, "return");

    const result = (
      performanceParam_log(text) / performanceParam_return(text)
    ).toFixed();

    resultArray.push(Number(result));

    /*
       Uncomment the below line to check
       which run was how many times faster.
       i.e. `run_123 ==> 20x faster`
     */
    // console.log(`\nrun_${_i + 1} ==> ${result}x faster\n`);
  }

  let total = 0;
  for (let _i = 0; _i < resultArray.length; _i++) {
    const result_element = resultArray[_i];
    total += result_element;
  }

  const average = total / times;

  console.log(`\n  return is ${average}x faster then console.log() on average`);
  console.log(`  In ${times} run(s)\n`);
}

Quite a long function we have now. Don't worry. Let's break it down.
As the name suggests, this function will run the tests a number of times. How many times? Well, as it takes a times parameter, we can pass that dynamically to the function. Then it declares an empty array to store all the results, which we can use later to calculate an average.
Then we start a for loop that runs "times" times and increases the value of _i by 1 on each run. Inside this loop, is the actual code that'll do our test.
Inside the loop, I'm calling the performanceCheck function twice. One for console.log() and one for the return statement. Notice that while calling the performanceCheck function, the second parameter I'm passing is the name of the function. Then after getting the corresponding returned values in performanceParam_log and performanceParam_return variable, I'm calculating a result. Notice that, performanceParam_log and performanceParam_return aren't value actual value. If we look at the performanceCheck function, it doesn't return any value. It returns a function that we can call with the necessary parameters. So as the logic goes, I'm calculating result by dividing the returned value of performanceParam_log and performanceParam_return. I'm also using the toFixed function to round up the value to a fixed number of integers after the dot(.) to reduce confusion.
And we're pretty much done here. We now just need to store the result value in the resultArray to calculate the average later (We need to store it as integers to do the math).
After all this, the only left thing is the average calculating part. Which relatively an easy job to do. We just need to declare a variable with the value of 0 to store the sum. We can name it as total. Then we just keep adding the elements of resultArray to total one by one.
After getting the total of all elements in resultArray We can calculate the average by dividing total with times or the length of resultArray.

Conclusion

So how this knowledge will help us?
Just as I started, in case you need to do so many console.log() in your production release, or a log inside a loop; don't do it directly. store all the values in a variable that you wanna log, and then just console.log() that variable once