8

As far as I know, scripts are downloaded and executed synchronously in javascript. Hence if we write the following code:

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

we'll see in console total time for download, parse and execute js. How we can exclude parsing time? Just add similar file, but with all code commented out. More or less, this technique should work.

The problem is this just doesn't work =)

I optimized that code, reduce execution time from 90ms to 25ms, but see the same ~100±10ms time for Chrome and ~160±15ms for Firefox.

Ok, I know I could use profiler, but the question is: "how to measure js parsing time correctly" and what did I measured btw. Research.reverse-engineering is very fun, but maybe there's someone who knows that field in depth.

3
  • A commented-out block of code is simply not the same as the uncommented code (as you discovered) Commented Mar 11, 2013 at 15:49
  • Following your own method, how about taking another measurement in the first line of guicore.js? That should execute right after it's parsed. Commented Mar 11, 2013 at 15:57
  • Have you tried using the Timeline view in Chrome? It splits out download time and evalation time Commented Mar 11, 2013 at 17:13

5 Answers 5

6

You cannot accurately measure script parse time independent of execution time using web APIs alone. Different browsers have different strategies for when they do parsing, and some of them will parse progressively as the script is executed, or even do "partial parsing" in cases where it's assumed a block of code is unlikely to immediately be executed (e.g. a function that is not an IIFE, see some details in the optimize-js README).

Using separate <script> tags is the most accurate way to at least capture both parsing and execution time. The only modification I would make to your snippet is this:

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

Note the use of the high-precision User Timing API which, as an added bonus, will show visualizations in the Chrome/Edge/IE dev tools (and tools like Windows Performance Analyzer and WebPageTest if you're so inclined).

Technically the 3rd <script> is not necessary, as you can just append the mark/measure to the end of the 2nd script. But the 1st <script> is certainly necessary to capture all parse time. You can verify in the dev tools that the marks/measures encompass all initial parsing and execution time.

Sign up to request clarification or add additional context in comments.

Comments

4

I know this is kind of an old question but I came across it while looking for a solution to this myself. You can use the dev tools in the browser of your choice to look at this but if you'd like to do it in code this is the method I ended up using.

The scriptLoadParseDuration function below will take a URL to a .js file, place it into a <script> element, and log the load/parse duration to the console.

Keep in mind that this will execute the <script> you are profiling within the current DOM context. So in the example below: jQuery is still accessible in the global scope even though the script was removed. The script could be extended to do all of this in an <iframe> to isolate it though.

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

Here is an example showing that jQuery is still in the global scope after the <script> removal.

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 Comment

Script load event is fired after the script has been executed, so this answer is incorrect - it will still include both parsing and execution time.
2

Open up Chrome and open the developer tools, the go to the "Timeline" tab. If you press the record button (filled in circle, bottom left) then reload the page it'll give you a fairly detailed timeline, broken down into specific types of activity (Send Request, Parse, Evaluate), timed down to the microsecond.

3 Comments

Yes, looks like Chrome fetch several js files simultaneously (but doesn't rovide data even to compiler before execution starts). I still can't find js parsing time though. Maybe, it is too small.
I think the parsing time for the actual JS is included in the "Evaluate Script" section. There is a Parse event but I think that's for HTML
well, I can measure execution time normally and with main method called 2 times. And then calculate using trivial arithmetics.
1

Very old question with a relatively new answer.

Date.now() returns a timestamp with millisecond accuracy. For an application to run at 60FPS, it must update the frame every 16ms. Our millisecond meter may not be accurate enough.

Introducing the Performace API in modern JS browsers, this allows for floating-point timestamps accurate to the microsecond.

Instead of Date.now() use window.performance.now() for measurements, there's a good guide on using the Performance API on HTML5Rocks.

Comments

1

Chrome DevTools actually has a hidden flag that shows V8 Parse and Compile time!

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

Outcome looks like this:

enter image description here

A quick guide is also available in the doc in the blue section below:

step by step guide (blue section)

After you enable the feature, you can profile a page and then click on "Bottom-Up" tab on the Performance tab in Chrome DevTools, and then make sure you "Group by Activity", and you should see the Compile and Parse time now.

Enjoy!

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.