in
Written by Harry Roberts on CSS Wizardry.
View this web page as Markdown.
Desk of Contents
Impartial writing is dropped at you through my fantastic
Supporters.
Google Chrome lately launched the Efficiency Extensibility
API, a method
of placing your code front-and-centre in Chrome’s Efficiency panel. Their very own
documentation is considerably dry and doesn’t actually state the advantages or outcomes
very clearly, so I spent a few hours trying into it and listed here are the important thing
takeaways.
Unsure use the Efficiency Extensibility API?
Learn up on the Person Timing
API’s efficiency.mark() and
efficiency.measure() first.
Should you:
- are all in favour of intently profiling particular, atomic elements of your
utility;- you’ll be able to intricately time bare-metal occasions.
- work in an organisation the place totally different groups contribute totally different code to the
similar front-end;- you’ll be able to create a customized part in DevTools for every workforce.
- want to collect wealthy (meta)knowledge about key elements of your runtime;
- you’ll be able to seize arbitrary knowledge as a part of normal APIs.
- present or eat APIs;
- you might monitor their response instances with ease and floor that info
to the front-end and DevTools.
- you might monitor their response instances with ease and floor that info
- keep a 3rd social gathering bundle that may very well be traced;
- you’ll be able to present clear signposting for key occasions (e.g. hydration) to your
customers, or;
- you’ll be able to present clear signposting for key occasions (e.g. hydration) to your
- are simply all in favour of efficiency tooling…
- …this text is for you.
Making Your Code a First Class Citizen
Chrome’s DevTools are
extremely highly effective, and are solely ever getting stronger, however this newest replace
palms a whole lot of management over to us! We will make our personal instrumentation a key
a part of our efficiency profiling expertise.
efficiency.mark() and efficiency.measure()
The Extensibility API is especially helpful in extending the
efficiency.mark() and .measure() Person Timings. Should you aren’t utilizing these
already, try to be. Should you aren’t conversant in them, it’s essential be earlier than
this publish will make sense to you. My 2022 publish Measure What You Influence,
Not What You
Affect is
a comparatively respectable introduction to the subject, however for now, this straightforward demo
ought to assist:
<script>efficiency.mark('cssStart');</script>
<hyperlink rel=stylesheet href=/app.css>
<script>
efficiency.mark('cssEnd');
efficiency.measure('cssTime', 'cssStart', 'cssEnd');
</script>
Right here, we drop a high-resolution timestamp — cssStart — utilizing efficiency.mark().
We then fetch a synchronous stylesheet, app.css, earlier than dropping a second
high-resolution timestamp, cssEnd, utilizing efficiency.mark() as soon as extra.
Lastly, we use efficiency.measure() to create a measure of the period of
the delta between cssStart and cssEnd.
We may log any of the above .mark()s or .measure()s to the console. For
instance, to get the beginning time of cssStart, we may do:
console.log(`CSS Begin: ${efficiency.getEntriesByName('cssStart')[0].startTime} ms`);
Or the period of the cssTime measure:
console.log(`CSS Length: ${efficiency.getEntriesByName('cssTime')[0].period} ms`);
Word that .mark()’s helpful property is startTime and .measures()’s is
period.

supply:console-api to scope your Consolemessages solely to issues logged to it. A lot cleaner.
We will use efficiency.mark() and .measure() in JavaScript, too, naturally:
efficiency.mark('jsStart');
// Simulate costly JavaScript execution
setTimeout(() => {
efficiency.mark('jsEnd');
efficiency.measure('jsTime', 'jsStart', 'jsEnd');
console.log(efficiency.getEntriesByName('jsStart')[0].startTime);
console.log(efficiency.getEntriesByName('jsTime')[0].period);
}, 1000);
Right here we’re simulating an costly little bit of scripting that we’d need to
instrument and optimise.
These are neat, however the significantly good factor about them is that Chrome
DevTools will robotically decide up these marks and measures, and show them
within the Timings monitor of the Efficiency panel:

cssTime and jsTime take upa proportional quantity of house to their period, however
jsEnd,a
.mark(), takes up a skinny sliver of the UI because it representsa second in time.
.mark()s are discovered above.measure()s.The good thing about the console.log() method is that it’s a lot quicker — you don’t
have to run a full efficiency profile, however the good thing about the Efficiency panel
technique is that you would be able to visualise the instances in context of your utility’s
runtime. The previous is nice when you simply want the quantity as shortly as attainable;
the latter is nice when you’re making an attempt to contextualise your work.
Truthfully, when you’ve by no means seen that earlier than, I dare say this text has supplied
a bunch of worth already! Subsequent, go and see put this into use with my
Measure What You Influence, Not What You
Affect
article which supplies good use-cases and examples for utilizing these bare-metal
metrics.
The Extensibility API
The brand new Extensibility API permits us to increase this performance. We will create
arbitrary customized tracks within the Efficiency panel, not limiting us to solely the
default Timings monitor, and we will add our personal metadata to those marks and
measures that can be utilized to floor extra info within the DevTools UI!
So as to take action, we have to write fairly much more code than the
efficiency.mark() and .measure()s we’ve simply checked out. We start by
extending the .mark() or .measure() with a devtools object that lives in
the particulars property, The entire level of this publish is to chop by means of the fluff
and present you, pragmatically, precisely what you do and don’t want.
Minimal Viable Measurement
Earlier than we will do something, within the Efficiency panel’s settings, we have to
allow Present customized tracks:

settings.
On this part, I’ll present you the naked minimal it’s essential make a begin with
the Extensibility API. Some features are obligatory and others, like colors, are
totally non-compulsory.
Beginning with .mark(), the dataType is required; nothing else is. Let’s
convert our jsEnd .mark() to make use of the Extensibility API:
efficiency.mark('jsEnd', {
element: {
devtools: {
dataType: 'marker'
}
}
});
We’re forgoing the rest for now, however this is step one to adopting the
Extensibility API for efficiency.mark():

jsEnd marker. That’s the prolongedefficiency.mark() in motion.Key enhancements:
- The marker is very obvious! It’s like a giant flag which makes recognizing
.mark()s infinitely simpler. - The marker has additionally positioned a dotted line all the best way down subsequent
tracks, together with the Foremost thread.
Nonetheless, there are two main downsides to date:
- The marker is as large because the textual content it incorporates — this will make issues
a bit of deceptive as markers now now not look like a time limit,
however probably a period. When you get used to this, you get used to it,
however at first, it’s simple to mistake a.mark()for a.meaasure(). - There’s completely no means of figuring out at what time the
.mark()was
fired! Even clicking the marker itself doesn’t present us any timestamp
info. Neither hovering or clicking the marker provides us the excessive
decision timing that we’d use a.mark()for within the first place:

this gorgeous weird.
To this finish, I’d be inclined to make use of .mark() much less as a timestamp and extra as a,
effectively, marker — it could shortly convey your consideration to the related a part of your
hint.
That’s your minimal viable .mark().
efficiency.measure() is a bit more helpful, although. Let’s convert cssTime
to its minimal viable model:
efficiency.measure('cssTime', {
begin: 'cssStart',
finish: 'cssEnd',
element: {
devtools: {
monitor: 'CSS'
}
}
});
We nonetheless have to cross within the reference begin .mark() through the begin:
property. Our finish marker, if omitted, defaults to proper now — when the
.measure() is being known as — or could be supplied explicitly through finish:. The
monitor property is obligatory, and this varieties our minimal viable .measure().
Word that we don’t want to provide the dataType property as its omission
defaults to dataType: 'track-entry', which is precisely what we’d like. Let’s see
what this appears like.
Hey! That’s fairly neat!

We now have our first customized monitor titled CSS
, sourced from our monitor:. That is the least we have to do to be able to make use of the
'CSS'
Extensibility API for efficiency.measure(). Subsequent, we’ll take it additional.
Maximising the Extensibility API
What I simply confirmed you was the naked minimal to rise up and operating with the
Extensibility API. .mark() is a bit of underwhelming, for my part, however the
means we will lengthen .measure() may be very cool. Let’s begin with the built-in
extensions we’ve.
Tracks and Colors
With each .mark() and .measure(), we will apply customized colors. Not arbitrary
or totally customized, like #f43059, however from DevTools’ personal palette: major,
primary-light, primary-dark, secondary, secondary-light,
secondary-dark, tertiary, tertiary-light, tertiary-dark, and error.
Let’s lengthen our .mark() from earlier than a bit of additional:
efficiency.mark('jsEnd', {
element: {
devtools: {
dataType: 'marker',
shade: 'secondary-dark'
}
}
});
Discover that our jsEnd marker is now a darkish pinky-purple:

secondary-dark.Simple sufficient! Subsequent, let’s add some extra descriptive tooltip textual content:
efficiency.mark('jsEnd', {
element: {
devtools: {
dataType: 'marker',
shade: 'secondary-dark',
tooltipText: 'Simulated JS Execution Full'
}
}
});
To be sincere, that is no higher, and definitely no extra handy, than simply
utilizing a unique string instead of jsEnd — this textual content hasn’t produced
a tooltip, however reasonably simply changed the marker’s textual content.
The takeaway up to now is that the Extensibility API is much less helpful for
efficiency.mark().

tooltipText merely replaces the marker’s textual content anddoesn’t really create a tooltip.
Lastly, for .mark(), we will cross in arbitrary metadata. That may very well be fairly
helpful for different builders choosing up a venture:
efficiency.mark('jsEnd', {
element: {
devtools: {
dataType: 'marker',
shade: 'secondary-dark',
tooltipText: 'Simulated JS Execution Full',
properties: [
['File', 'app.js'],
['Function', 'setTimeout()']
]
}
}
});
Above, I’ve handed in almost-pointless knowledge as an instance the purpose, however I’m
positive you’ll be able to consider your individual helpful use-cases.

All the options I simply confirmed you (shade, tooltipText, and properties)
apply equally to efficiency.measure(), so let’s leap forward and produce our
efficiency.measure() instance updated in a single go:
efficiency.measure('cssTime', {
begin: 'cssStart',
finish: 'cssEnd',
element: {
devtools: {
monitor: 'CSS',
shade: 'secondary-dark',
tooltipText: 'Exterior CSS fetched and parsed',
properties: [
['URL', app.css],
['Transferred Size', 29.3 KB],
['Decoded Body Size', 311.8 KB],
['Queuing & Latency', 104 ms],
['Download', 380 ms]
]
}
}
});
I’ve added a shade, a tooltipText, and a few made up metadata in
properties. Word that I really constructed a demo that used the Useful resource Timing
API to seize these numbers for actual. That code is in the appendix.

.measure() really will get a correct tooltip, and wehave wealthy metadata within the Abstract pane.
Now that is extra prefer it!
- We nonetheless have our devoted CSS monitor;
- The
tooltipTextreally appears and acts like a tooltip; - The Abstract pane has a number of good, wealthy metadata!
That is the place I see the Extensibility API changing into significantly helpful. There’s
only one thing more I need to present you: monitor teams.
Observe Teams
We created a customized CSS monitor utilizing monitor: 'CSS'. We would need to make
a monitor for JS, API calls, you identify it. We will then take all of those tracks and
group them right into a monitor group.
Observe teams are helpful if, say, we need to monitor first- and third-party
attribution individually, or if our codebase has totally different groups who need to
isolate their instrumentation from one another. They’re additionally extremely simple to
arrange. Let’s evolve our .measure() a bit of extra:
efficiency.measure('cssTime', {
begin: 'cssStart',
finish: 'cssEnd',
element: {
devtools: {
monitor: 'CSS',
trackGroup: 'First Social gathering',
shade: 'secondary-dark',
tooltipText: 'Exterior CSS fetched and parsed',
properties: [
['URL', app.css],
['Transferred Size', 29.3 KB],
['Decoded Body Size', 311.8 KB],
['Queuing & Latency', 104 ms],
['Download', 380 ms]
]
}
}
});
And let’s shortly return and add trackGroup: 'First Social gathering' to our JS’s
.measure():
efficiency.measure('jsTime', {
begin: 'jsStart',
finish: 'jsEnd',
element: {
devtools: {
monitor: 'JS',
trackGroup: 'First Social gathering',
shade: 'secondary-dark',
tooltipText: 'Simulated JS Execution Full',
properties: [
['File', 'app.js'],
['Function', 'setTimeout()']
]
}
}
});
…and what will we get?

a First Social gathering monitor group.
Now we’ve a monitor group known as First Social gathering which incorporates each a CSS and
a JS sub-track!
I hope you’ll be able to already start to think about and envision use-cases for tracks and
monitor teams. Should you’re profiling and instrumenting your utility with
efficiency.mark() and efficiency.measure() already, the concept of getting it
all organised absolutely excites you!
Recap
The syntax for all of that is very repetetive and cumbersome, so all I might say
is begin with as little as you will get away with. Personally, I might not
suggest utilizing the Extensibility API for efficiency.mark(), so I’m not going
to confuse folks by recapping it.
For efficiency.measure(), all you really want to get off the bottom is:
efficiency.measure('<identify>', {
begin: '<begin>',
finish: '<finish>',
element: {
devtools: {
monitor: '<track-name>'
}
}
});
This can robotically transfer this measure into its personal customized monitor named, in
this case, <track-name>.
Subsequent up, I’d counsel trying into monitor teams so that you could higher organise
your self:
efficiency.measure('<identify>', {
begin: '<begin>',
finish: '<finish>',
element: {
devtools: {
monitor: '<track-name>',
trackGroup: '<group-name>'
}
}
});
Maybe a bunch for any code that comes out of your design system or your individual
first social gathering utility, with sub-tracks for JS, API calls, and many others. It truly is up
to you.
Past that, we’re principally fascinated about including metadata and customized colors, however
don’t fear about that till you’ve bought the mechanism dialled in.
Third Events
Should you work on a framework or a 3rd social gathering that devices its personal Person
Timings, please contemplate shifting them into your individual monitor group. It might be good
to see, for instance, Subsequent.js route-change or hydration timings in their very own
place.
Appendix
Useful resource Timing API Instance
Drop this straight into an HTML file, hearth it up in Chrome, and it’ll Simply
Work™.
<!doctype html>
<html lang=en-gb>
<meta charset=utf-8>
<meta identify=viewport content material="width=device-width, minimum-scale=1.0">
<title>Extensibility API</title>
<script>
efficiency.mark('cssStart', {
element: {
devtools: {
dataType: "marker",
tooltipText: 'Get Bootstrap CSS from CDN',
shade: "secondary-light"
}
}
});
</script>
<hyperlink rel=stylesheet href=https://cdn.jsdelivr.internet/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css id=jsCSS>
<script>
efficiency.mark('cssEnd');
// Seize stylesheet’s timing metadata.
const css = doc.getElementById('jsCSS');
const cssURL = css.href;
const cssTimingInformation = efficiency.getEntriesByName(cssURL)[0];
const cssTransferSize = (cssTimingInformation.transferSize / 1024).toFixed(2);
const cssDecodedBodySize = (cssTimingInformation.decodedBodySize / 1024).toFixed(2);
const cssLatencyDuration = (cssTimingInformation.responseStart - cssTimingInformation.startTime).toFixed(2);
const cssdownloadDuration = (cssTimingInformation.responseEnd - cssTimingInformation.responseStart).toFixed(2);
</script>
<script>
efficiency.measure('cssTime', {
begin: 'cssStart',
finish: 'cssEnd',
element: {
devtools: {
dataType: 'track-entry',
trackGroup: 'Third Social gathering Instrumentation',
monitor: 'CSS',
tooltipText: 'CSS Downloaded and Parsed',
shade: 'secondary-light',
properties: [
['URL', cssURL],
['Transferred Size', `${cssTransferSize} KB`],
['Decoded Body Size', `${cssDecodedBodySize} KB`],
['Queuing & Latency', `${cssLatencyDuration} ms`],
['Download', `${cssdownloadDuration} ms`]
]
}
}
});
</script>

