如何衡量脚本执行和*解析*时间?

时间:2013-03-11 15:40:32

标签: javascript profiling

据我所知,脚本是在javascript中同步下载和执行的。 因此,如果我们编写以下代码:

<script type='text/javascript'>console.time('core')</script>
<script type='text/javascript' src="guicore.js"></script>
<script type='text/javascript'>console.timeEnd('core')</script>

我们将在控制台中看到下载,解析和执行js的总时间。 我们如何排除解析时间?只需添加类似的文件,但所有代码都已注释掉。或多或少,这种技术应该有效。

问题是这不起作用=)

我对该代码进行了优化,将执行时间从90毫秒减少到25毫秒,但Chrome浏览器的时间约为100±10毫秒,Firefox的时间约为160±15毫秒。

好的,我知道我可以使用探查器,但问题是:“如何正确测量js解析时间”以及我测量了什么。 Research.reverse-engineering非常有趣,但也许有人深入了解这个领域。

5 个答案:

答案 0 :(得分:4)

我知道这是一个古老的问题,但我在寻找解决方案时遇到了这个问题。你可以在你选择的浏览器中使用开发工具来查看这个,但如果你想在代码中这样做,这就是我最终使用的方法。

下面的scriptLoadParseDuration函数将获取.js文件的URL,将其放入<script>元素,并将加载/解析持续时间记录到控制台。

请记住,这将执行您在当前DOM上下文中进行概要分析的<script>。因此,在下面的示例中:即使已删除脚本,仍可在全局范围内访问jQuery。可以扩展脚本以在<iframe>中完成所有这些操作以隔离它。

function scriptLoadParseDuration(url) {
  var start;
  var script = document.createElement('script');
  
  // <script> must be attached to the document to actually load the file
  document.querySelector('html').appendChild(script);
  
  // Calculate load/parse duration once script has loaded
  script.addEventListener('load', function scriptLoad() {   
    // Calculate load/parse duration
    console.log('Duration: ' + (Date.now() - start) + 'ms');
    
    // Remove <script> from document
    script.parentElement.removeChild(script);
  }, false);
  
  // Get current time in milliseconds
  start = Date.now();
  
  // Setting the `src` starts the loading. Math.random is used to make sure it is an uncached request
  script.src = url + '?' + Math.floor(Math.random() * 9e9);
}

var url = 'https://code.jquery.com/jquery-3.0.0.min.js';

scriptLoadParseDuration(url);

以下示例显示jQuery移除后<script>仍在全局范围内。

function scriptLoadParseDuration(url) {
  var start;
  var script = document.createElement('script');
  
  console.log('`jQuery` before attaching: ' + typeof jQuery);
  
  // <script> must be attached to the document to actually load the file
  document.querySelector('html').appendChild(script);
  
  // Calculate load/parse duration once script has loaded
  script.addEventListener('load', function scriptLoad() {   
    // Calculate load/parse duration
    console.log('Duration: ' + (Date.now() - start) + 'ms');

    console.log('`jQuery` once attached: ' + typeof jQuery);
    // Remove <script> from document
    script.parentElement.removeChild(script);
    console.log('`jQuery` after detach: ' + typeof jQuery);
  }, false);
  
  // Get current time in milliseconds
  start = Date.now();
  
  // Setting the `src` starts the loading. Math.random is used to make sure it is an uncached request
  script.src = url + '?' + Math.floor(Math.random() * 9e9);
}

var url = 'https://code.jquery.com/jquery-3.0.0.min.js';

scriptLoadParseDuration(url);

答案 1 :(得分:3)

您不能仅使用Web API来独立于执行时间准确地测量脚本解析时间。不同的浏览器在进行解析时会采用不同的策略,其中一些会在执行脚本时逐步进行解析,或者在假定不太可能立即执行代码块的情况下甚至进行“部分解析”(例如,一个函数那不是IIFE,请参见一些详细信息in the optimize-js README)。

使用单独的<script>标签是至少捕获两者解析和执行时间的最准确方法。我要对您的代码段进行的唯一修改是:

<script>
  performance.mark('start');
</script>
<script src="myscript.js"></script>
<script>
  performance.mark('end');
  performance.measure('total', 'start', 'end');
</script>

请注意,高精度User Timing API的使用(作为额外的好处)将在Chrome / Edge / IE开发人员工具(以及Windows Performance Analyzer和WebPageTest之类的工具)中显示可视化效果)。

从技术上讲,第三个<script>不是必需的,因为您可以将标记/小节附加到第二个脚本的末尾。但是第一个<script>当然是捕获所有解析时间所必需的。您可以在开发工具中验证标记/度量是否包含所有初始解析和执行时间。

答案 2 :(得分:2)

打开Chrome并打开开发人员工具,转到“时间轴”标签。如果按下录制按钮(填充圆圈,左下角)然后重新加载页面,它将为您提供相当详细的时间线,分解为特定类型的活动(发送请求,解析,评估),时间缩短到微秒。

答案 3 :(得分:1)

Chrome DevTools实际上有一个隐藏的标志,用于显示V8解析和编译时间!

https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/javascript-startup-optimization#parsecompile

结果如下:

enter image description here

文档的下面蓝色部分也提供了快速指南:

step by step guide (blue section)

启用此功能后,您可以分析页面,然后在Chrome DevTools的“性能”选项卡中单击“自下而上”选项卡,然后确保“按活动分组”,并且应该看到“编译和现在解析时间。

享受!

答案 4 :(得分:0)

很老的问题,有一个相对较新的答案。

Date.now()返回精确到毫秒级的时间戳。对于以60FPS运行的应用程序,它必须每16ms更新一次帧。我们的毫秒表可能不够准确。

在现代JS浏览器中引入Performace API,这允许浮点时间戳精确到微秒。

而不是Date.now()使用window.performance.now()进行测量,这是使用Performance API on HTML5Rocks的良好指南。