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.
To use it, just call
JS one-liners inlined directly into HTML will do as well:
<p>What a beautiful text</p> <script> performance.mark("afterText"); </script>
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!
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>
Opening this in browser will mark two events: the one before stylesheet link, and one after. Check'em out:
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
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>
Now let's see how this measure thing looks in browser:
Cool, we can now just look at
duration instead of doing math. Yay computers!
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:
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.
Getting performance marks with your browser is easy:
- Go to the developer tools of your browser
- Put down
performance.getEntriesByType('mark')and here they are!
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.
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!
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!