Home > Enterprise >  Why is the split() method approx. 2x slower when the result is pushed to an array?
Why is the split() method approx. 2x slower when the result is pushed to an array?

Time:01-05

Consider the following code snippet:

function split() {
  let time = 0;
  let result = [];
  for (let i = 0; i < 10 * 1000 * 1000; i  ) {
    let start = performance.now();
    let words = "foo bar baz".split(" ");
    let end = performance.now();
    time  = (end - start);
    // result.push(words);
  }
  console.log(`Time needed: ${time}ms`);
}

The output of this code is something like:

Time needed: 2664ms.

However, with the line // result.push(words); uncommented, the output is something like:

Time needed: 4991ms.

That's approx. 2x slower (note that I'm measuring only the time needed by split(), but not push()). Can someone explain me why?

CodePudding user response:

You are taking your time 10.000.000 of times in a loop and get a overall sum of 2665 milliseconds. If "calculate" the length of one loop iteration, it is 0.0002665 milliseconds, ie about 0.27 microseconds. That's way below the accuracy of performance.now, which according to the docs is 5 microseconds (ie more than 20 times as big). Thus what you are measuring is more or less random ...

And just for demonstration purposes (yes, the measurement is still inaccurate): Doing both variants 1000 times and suming up the duration for each run will sum up to more or less the same, because the inaccuracies will cancel out each other. BTW I ran this test 4 times, and 3 times, split2() was "faster" ...

function split1() {
  let time = 0;
  let result = [];
  for (let i = 0; i < 10 * 1000; i  ) {
    let start = performance.now();
    let words = "foo bar baz".split(" ");
    let end = performance.now();
    time  = (end - start);
    //result.push(words);
  }
  return time;
}

function split2() {
  let time = 0;
  let result = [];
  for (let i = 0; i < 10 * 1000; i  ) {
    let start = performance.now();
    let words = "foo bar baz".split(" ");
    let end = performance.now();
    time  = (end - start);
    result.push(words);
  }
  return time;
}


let total1 = 0;
for (let i = 0; i< 1000; i  )
  total1  = split1();
  
let total2 = 0;
for (let i = 0; i< 1000; i  )
  total2  = split2();
  
console.log(total1.toFixed(1), total2.toFixed(1));

CodePudding user response:

performance.now() does not have the necessary accuracy to measure what you're trying to measure. The browser deliberately returns an inaccurate number from performance.now() in order to combat exploits like spectre. So in both cases, the numbers you are seeing are not going to be accurate.

As for why you're getting different inaccurate numbers, here's my speculation. I'm guessing that most of the time, end - start is 0, because both timestamps are rounded to the same thing. So what you're really counting is the number of times where the rounding of the timestamp flips from one number to the next. Your first code might run through the loop 10 times, with 9 of them reporting 0ms, and 1 of them reporting 1ms. But then when you make the whole thing take longer, now it only takes 5 times through the loop for enough time to elapse that the rounding goes the other way. And so out of 10 times through the loop, 8 report 0ms and 2 report 1ms.

  •  Tags:  
  • Related