为什么 split() 方法大约是。将结果推送到数组时慢 2 倍?

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

考虑以下代码片段:

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

这段代码的输出是这样的:

Time needed: 2664ms.

然而,在 // result.push(words); 行未注释的情况下,输出类似于:

Time needed: 4991ms.

那是大约。慢 2 倍(请注意,我只测量了 split() 所需的时间,而不是 push())。有人可以解释一下为什么吗?

您在一个循环中花费了 10.000.000 次时间,总和为 2665 毫秒。如果“计算”一次循环迭代的长度,则为0.0002665毫秒,即约0.27微秒。这远低于 performance.now 的精度,根据 docs,后者是 5 微秒(即大 20 倍以上)。因此,您正在测量的或多或少是 运行dom ...

并且仅出于演示目的(是的,测量仍然不准确):将两个变体都做 1000 次并总结每个变体的持续时间 运行 总和或多或少相同,因为不准确会互相抵消。顺便说一句,我 运行 这个测试 4 次,3 次,split2() 是“更快”...

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

performance.now() 没有必要的准确性来衡量您要衡量的内容。浏览器故意 returns 来自 performance.now() 的不准确数字,以对抗 spectre 这样的攻击。所以在这两种情况下,您看到的数字都不会准确。

至于为什么您得到 不同 不准确的数字,这是我的推测。我猜大多数时候,end - start 是 0,因为两个时间戳都四舍五入到相同的东西。所以你真正计算的是时间戳的舍入从一个数字翻转到下一个数字的次数。您的第一个代码可能 运行 循环 10 次,其中 9 次报告 0 毫秒,其中 1 次报告 1 毫秒。但是当你让整个事情花费更长的时间时,现在只需要 5 次循环就可以有足够的时间流逝,舍入会以相反的方式进行。因此,在循环的 10 次中,8 次报告 0 毫秒,2 次报告 1 毫秒。