DEV Community

Cover image for  "Performance marks: the missing manual, Part 1"
Eugene Chekan
Eugene Chekan

Posted on • Edited on • Originally published at Medium

"Performance marks: the missing manual, Part 1"

Image by Viktoriiaa

performance.mark() is a part of User Timing API. Arguably, it is the most useful performance-related method we have in browsers now because its application possibilities are far beyond just “mark this timestamp for me”, especially when combined with deep understanding of how browsers actually work.

Basic Usage

To use it, just call performance.mark() and pass mark name as a parameter within any JavaScript code:

performance.mark("fontsLoaded");
Enter fullscreen mode Exit fullscreen mode

This will add a PerformanceMark to the performance timeline.
To delete a mark, make a call to the performance.clearMarks() method:

performance.clearMarks("fontsLoaded");
Enter fullscreen mode Exit fullscreen mode

JS one-liners inlined directly into HTML will do as well:

<p>What a beautiful text</p>
<script>
  performance.mark("afterText");
</script>
Enter fullscreen mode Exit fullscreen mode

I know what you're thinking: “Hey JS is mostly single-threaded, can I mark the moment when browser reaches exact line in the document?”. For the most part, yes, you can. Let's try this out!

Mark all the things

First, a bit of theory 🤓. Most of the time, document parsing and JS execution is done in a single thread, with respect for document structure from a first line to the last one. When browser meets, say, a <link> to the stylesheet or a script, it pauses execution, downloads the resource it stumbled on, parses and executes it, and only then continues with parsing and executing stuff below. This concept — render-blocking resources — is crucial for achieving fast rendering timings and brilliantly covered by Ilya Grigorik in his talks and free online course.

Now, optimizations aside, you may want to know how much time do you lose due to render being blocked by resources. Take a look at this snippet:

<html>
  <head>
  <title>Performance marks demo #1</title>
  <script>performance.mark('parsing:css:start');</script>
  <link rel="stylesheet" href="shiny-style.css">
  <script>performance.mark('parsing:css:end');</script>
  </head>
  <body>
    <p>What a beautiful text</p>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

Opening this in browser will mark two events: the one before stylesheet link, and one after. Check'em out:
render-blocking CSS performance marks
Whoa 😱! It took browser near 80 ms to download, parse and apply our shiny stylesheet, faster than a blink of an eye. Not so fast for one CSS selector we have there, though.

On the bright side, you now know how to measure for how long rendering is blocked by resources. Wait, did I say measure?

Measures

We all ❤️ math, don't we? But when it comes to actual calculations, we like to make computers do it. Performance marks are no exception and we have handy performance.measure() method which, well, measures distance between two marks. Let's add it to our HTML snippet:

<html>
  <head>
  <title>Performance marks demo #2: measures</title>
  <script>performance.mark('parsing:css:start');</script>
  <link rel="stylesheet" href="shiny-style.css">
  <script>
    performance.mark('parsing:css:end');
    performance.measure('blocking-styles', 'parsing:css:start', 'parsing:css:end');
  </script>
  </head>
  <body>
    <p>What a beautiful text</p>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

Now let's see how this measure thing looks in browser:
performance measure example
Cool, we can now just look at measure's duration instead of doing math. Yay computers!

Mark-fu

Me myself as well as some other developers prefer to use some kind of namespacing when setting up marks to organize taxonomy across different mark and event types:

performance.mark("fonts:roboto:load");
performance.mark("parsing.head.start");
Enter fullscreen mode Exit fullscreen mode

That is, you just separate namespaces with colon or dot and your marks are getting nice structure. Of course you can use anything (🐰, anyone?) to separate namespaces, not just dots and colons. There is no solid standard about performance marks namespacing and you are welcome to use whatever separator you want to use, pretty much like CSV format.

Retrieve your marks

During development

Getting performance marks with your browser is easy:

  1. Go to the developer tools of your browser
  2. Switch to JavaScript Console tab
  3. Put down performance.getEntriesByType('mark') and here they are!

From real users

Now, the hardest part is to retrieve these marks from your real users, and we're at Taki care about marks a lot. We are currently developing Marks'n'Measures Dashboard, although marks are already visible in our Waterfall view.

Webpagetest, as well as WPT-based MachMetrics & SpeedCurve, do support performance marks to some extent and you can get a glance at marks in Performance Timeline with these tools. If you haven't heard about WPT, go check it out: it is one of the best #webperf tools out there, it's completely free yet carries a whole lot of features. I literally use it on a daily basis and do love it.

Who use it?

There's a couple of examples of performance marks in wild I know of: Google Maps and Optimizely. They set up marks throughout their client-side JS, so if you have GMaps embeded, or do run some Optimizely experiments, check out performance entries with your devtools on those pages!

What next?

In coming articles I will show a lot more of advanced level mark-fu and tell you about differences across different browsers in marks handling (you didn't even thought everything will work the same across all the browserzoo we're developing to, do you?😉).

If you know some other examples of marks in the wild other than Google Maps and Optimizely, please do share them in comments below. And of course I encourage you to share your experience with marks, would love to take a look at other devs approach to marks.

And remember, #perfmatters!

Top comments (6)

Collapse
 
ben profile image
Ben Halpern

Awesome walk through Eugene

Collapse
 
vanux profile image
vanux

Other web sites using this include:

cars.com - "pageload, searchFormLoaded, pageImpressionFired, dtmPageViewFired

Microsoft.com - footer Duration, Main area duration, Header Duration

airbnb.com - time to airbnb interactive

Collapse
 
mighty_peach profile image
mighty_peach

Eugene thanks! Great article!

Collapse
 
borisschapira profile image
Boris Schapira

Very interesting post, thank you. Can't wait for the advance use cases!

Collapse
 
goshishah profile image
shujaat ali

That was awesome, once i was think about to check my function code performance time, Right know i can check it easily, Thanks for sharing a great article (Y)

Collapse
 
borisschapira profile image
Boris Schapira • Edited

Hey, any news about a part 2?