代码之家  ›  专栏  ›  技术社区  ›  Black Mamba

在向用户显示输出的同时,准确地度量Javascript函数的性能

  •  4
  • Black Mamba  · 技术社区  · 6 年前

    正如您在下面的代码中看到的,当我增加字符串的大小时,会导致0毫秒的差异。而且,随着字符串计数的不断增加,存在不一致性。

    我做错什么了吗?

    let stringIn = document.getElementById('str');
    let button = document.querySelector('button');
    
    button.addEventListener('click', () => {
      let t1 = performance.now();
      functionToTest(stringIn.value);
      let t2 = performance.now();
      console.log(`time taken is ${t2 - t1}`);
    });
    
    function functionToTest(str) {
      let total = 0;
      for(i of str) {
       total ++;
      }
      return total;
    }
    <input id="str">
    <button type="button">Test string</button>

    我试过用 await 但结果是相同的(参见下面的代码片段)。包含下面代码的函数是 async :

    let stringArr = this.inputString.split(' ');
    let longest = '';
    const t1 = performance.now();
    let length = await new Promise(resolve => {
      stringArr.map((item, i) => {
        longest = longest.length < item.length ? longest : item;
        i === stringArr.length - 1 ? resolve(longest) : '';
      });
    });
    const diff = performance.now() - t1;
    console.log(diff);
    this.result = `The time taken in mili seconds is ${diff}`;
    

    我也试过了 this answer as ,但也不一致。

    我试着用 console.time 功能,但它不允许渲染时间,也不准确。


    更新 :我想构建一个类似 jsPerf ,这将是非常相似的,但有不同的目的。主要是我想比较不同的功能,这将取决于用户的输入。

    2 回复  |  直到 6 年前
        1
  •  7
  •   Andrii Muzalevskyi    6 年前

    有三件事可以帮助你理解发生了什么:

    1. 浏览器正在减少 performance.now() 精度,以防止熔毁和幽灵攻击,所以铬提供最大0.1毫秒的精度,FF 1ms,等等,这使得不可能测量小的时间范围。如果功能非常快- 0 ms是可以理解的结果。(感谢@kaido)来源: paper , additional links here

    2. 多线程环境中的任何代码(包括JS)都不会以恒定的性能执行(至少由于OS线程切换)。因此,获得几个单一运行的一致值是不可能实现的目标。得到一些精确的数字- 函数应该执行多次,取平均值 . 这甚至可以在低精度下工作 表演。现在() . (无聊的解释:如果函数比0.1毫秒快得多,浏览器通常会给出0毫秒的结果,但有时某个函数运行会中彩票,浏览器会返回0.1毫秒。。。功能越长,中彩票的几率就越大)

    3. 在大多数JS引擎中都有“优化编译器”。它优化了常用的函数。优化是昂贵的,所以JS引擎只优化常用的函数。这解释了几次运行后性能的提高。首先,函数以最慢的方式执行。经过多次执行,它得到了优化,性能得到了提高。( 应该增加热身训练吗? )


    我可以得到非零的数字在您的代码snipet-通过复制粘贴到输入70kb的文件。在第三次运行后,函数被优化,但即使在这之后-性能也不是恒定不变的

    time taken is 11.49999990593642
    time taken is 5.100000067614019
    time taken is 2.3999999975785613
    time taken is 2.199999988079071
    time taken is 2.199999988079071
    time taken is 2.099999925121665
    time taken is 2.3999999975785613
    time taken is 1.7999999690800905
    time taken is 1.3000000035390258
    time taken is 2.099999925121665
    time taken is 1.9000000320374966
    time taken is 2.300000051036477
    

    第1点说明

    假设发生了两个事件,目标是在它们之间找到时间。 第一个事件发生在时间A,第二个事件发生在时间B。浏览器对精确值A和B进行四舍五入并返回它们。

    要查看的几个案例:

    A       B       A-B         floor(A)    floor(B)    Ar-Br      
    12.001  12.003  0.002       12          12          0
    11.999  12.001  0.002       11          12          1
    
        2
  •  2
  •   vorillaz    6 年前

    浏览器比我们想象的要聪明,有很多的改进和缓存技术用于内存分配、可重复代码执行、按需CPU分配等等。例如V8,驱动Chrome和节点.js caches code execution cycles and results . 此外,您的结果可能会受到代码执行时浏览器使用的资源的影响,因此即使执行多次,结果也可能会有所不同。

    正如您所提到的,您正在尝试创建一个jsPerf克隆 Benchmark.js ,此库由jsPerf开发团队使用。

    运行性能分析测试非常困难,我建议在节点.js具有预定义和预分配资源的环境,以便获得结果。

        3
  •  0
  •   AnyWhichWay    4 年前

    你也许该看看什么 https://github.com/anywhichway/benchtest 它只是重用Mocha单元测试。注意,单元级的性能测试应该只是性能测试的一部分,还应该使用模拟真实环境的模拟器,并在应用程序级测试代码,以评估性能 网络影响、模块交互等。