WEBVTT

00:00.000 --> 00:19.720
How many of you have heard of the long animation frame or low-FAPI?

00:19.720 --> 00:20.960
A few.

00:20.960 --> 00:28.080
How many of you ship JavaScript on your web pages?

00:28.080 --> 00:32.520
Are you going to have an interesting conversation?

00:32.520 --> 00:39.160
So I've been working in helping people measure the speed of their sites for, oh god, 12 years

00:39.160 --> 00:41.920
I think, it's all I do.

00:41.920 --> 00:48.920
And one of the things I found is it's really tempting to measure or focus on measuring what's

00:48.920 --> 00:51.200
easy to measure.

00:51.200 --> 00:55.360
You know, if we can measure it, we can do something about it.

00:55.360 --> 01:03.400
And often, what we really need to focus on is the things that are difficult to measure.

01:03.400 --> 01:10.920
Robin tells a lot, I was going to say endlessly, but that's probably very generous about

01:10.920 --> 01:12.480
networking.

01:12.480 --> 01:19.080
And we can measure what's happening over the network in lab environments, using dev tools,

01:19.080 --> 01:22.200
or web-page tests, or similar products.

01:22.200 --> 01:27.120
And we can also use APIs like resource timing to measure some of that network activity

01:27.120 --> 01:31.000
in the browser as we deliver content to our visitors.

01:31.000 --> 01:39.240
So we've got a pretty good handle on what's going on from a network point of view.

01:39.240 --> 01:44.720
Other things are kind of a bit more difficult.

01:44.720 --> 01:51.120
And JavaScript has been traditionally more difficult.

01:51.120 --> 02:01.040
As time has gone past, we've ended up shipping more and more JavaScript to people visiting

02:01.040 --> 02:02.640
our pages.

02:02.640 --> 02:04.880
We've built rich applications.

02:04.880 --> 02:10.000
Some of those are our client-side rendered, some are web pages full of marketing tags.

02:10.000 --> 02:17.400
And overall, the matter scripts we're delivering has grown over time.

02:17.400 --> 02:23.760
And the challenge with a script is, it's not like an image.

02:23.760 --> 02:27.680
You download an image, you render it on the page.

02:27.680 --> 02:32.160
With scripts, there's more than just download size to consider.

02:32.160 --> 02:38.680
We have to think about what happens when that script actually gets to run on our vests

02:38.680 --> 02:47.760
as a device, whether it's iPhone 15 or 16, which are fast devices, or a crappy $40 Android

02:47.760 --> 02:48.760
device.

02:48.760 --> 02:51.040
So you have to think about that.

02:51.040 --> 02:57.000
And a while ago, it's about a decade.

02:57.000 --> 03:00.640
Somebody said you don't need to worry about JavaScript size.

03:00.640 --> 03:05.280
What you have to do is ship one less image, one less jpeg, and you can add more JavaScript

03:05.280 --> 03:08.560
to your page.

03:08.560 --> 03:17.560
I think they would, having talked in the bad it, they wouldn't make that statement today.

03:17.560 --> 03:22.280
Because have you ever seen a jpeg that can do this?

03:22.280 --> 03:27.720
And this is, I don't know, 200 bytes.

03:27.720 --> 03:31.560
To save you reading it, what it does is add to three second delay every time you try

03:31.560 --> 03:34.160
and move your mouse.

03:34.200 --> 03:40.560
So, tiny bit of code, you can destroy the experience of your view of this stuff.

03:40.560 --> 03:46.360
And it's a bit of a silly example, but we get real world equivalents.

03:46.360 --> 03:53.800
Five or six years ago, I was working with a US company who had, they built their own clients

03:53.800 --> 03:56.000
I'd rendering framework.

03:56.000 --> 03:59.000
And they were using mutation observers.

03:59.000 --> 04:04.040
And as the page was being constructed, mutation observers were running for so long that

04:04.040 --> 04:07.640
the browser stopped making network requests for two seconds.

04:07.640 --> 04:14.640
So, it's easy to screw up your page with JavaScript.

04:14.640 --> 04:21.240
And we may not really see it because it's on our visit as device.

04:21.240 --> 04:28.640
And we come across all sorts of situations where scripts, running on a page,

04:28.640 --> 04:33.920
can get an interfere with somebody tries to scroll smoothly, or as they try to interact.

04:33.920 --> 04:42.920
And we don't, or up until 18 months ago, we've not really had any way to understand what's

04:42.920 --> 04:44.920
going on.

04:44.920 --> 04:47.920
We tried to measure it once before.

04:47.920 --> 04:55.560
The long-tax API, which is only in Chromium browsers, was an attempt to try and measure

04:55.560 --> 04:59.120
how busy our main thread was.

04:59.120 --> 05:06.600
What the long-task API does is generate an entry in the performance timeline for every

05:06.600 --> 05:09.680
main thread task that's over 50 milliseconds.

05:09.680 --> 05:15.600
And if you use the Chrome DevTools, it's the, when you profile a page, it's the ones that

05:15.600 --> 05:20.240
have that red hashing over the top.

05:20.240 --> 05:25.600
So we had this API, it could tell us when there were tasks over 50 milliseconds.

05:25.600 --> 05:29.960
We could report it back in analytics, and we're using monitoring tools.

05:29.960 --> 05:36.840
So we can understand how much time of visitors spent waiting for long tasks.

05:36.840 --> 05:42.880
And we have this in our products, some of our competitors have it as well.

05:42.880 --> 05:49.040
And the next biggest question we always get from customers is, okay, so what's causing

05:49.040 --> 05:51.720
these long tasks?

05:51.720 --> 05:52.920
Because we want to go fix them.

05:52.920 --> 05:56.200
We want to make others experience better.

05:56.200 --> 06:03.360
And the harsh reality is we don't know, because the API doesn't tell us.

06:03.360 --> 06:08.200
We get a start time when we get a duration, so we can tell when it happened, how long

06:08.200 --> 06:19.440
it lasted for, but in attribution, we get absolutely nothing of use, which kind of makes

06:19.440 --> 06:26.560
me sad, because I care deeply about making people's experiences better.

06:26.560 --> 06:36.600
Fortunately, about 18 months ago, you and a half, perhaps a bit more bit less.

06:36.600 --> 06:42.440
The Chrome team proposed something called the Long Animation for AMZ API, or LOWAF, you

06:42.440 --> 06:45.440
will hear it referred to.

06:45.440 --> 06:53.760
And it takes a slightly different approach to measuring long tasks on the May thread.

06:53.760 --> 06:57.240
What it does is it measures it from a visual perspective.

06:57.240 --> 07:11.880
So when the browser starts to render a frame to the page, it tracks how many times, or how

07:11.880 --> 07:15.560
long a frame, how much longer than 50 milliseconds of frame is?

07:15.560 --> 07:21.800
So we're trying to render frames at 60 frames per second to give a smooth experience.

07:21.800 --> 07:29.880
And what LOWAF does is notify us when frames are starting to be longer than 50 milliseconds.

07:29.880 --> 07:32.280
And in DevTools terms, you can think of it this way.

07:32.280 --> 07:35.960
We have the start of the frame where we pass the HTML.

07:35.960 --> 07:41.560
In this case, where it's passing HTML, this one's quite long, because it's the

07:41.640 --> 07:43.000
start of a page.

07:43.000 --> 07:48.800
And then the end of it is when the browser actually starts to paint.

07:48.800 --> 07:57.280
It's not quite when the frame is presented to this, but it's getting there.

07:57.280 --> 08:01.560
And it's a very big Chromey in-base browsers right now.

08:01.560 --> 08:04.080
It's certainly Chrome and Edge.

08:04.080 --> 08:09.240
It's not available in Safari or Firefox.

08:09.240 --> 08:10.440
It may or may not come to them.

08:10.440 --> 08:14.280
There are some challenges, because there's Robin talked about the network stack being

08:14.280 --> 08:16.120
different in browsers.

08:16.120 --> 08:23.480
How browsers track what work they're doing internally varies enormously as well.

08:23.480 --> 08:26.080
And there are two ways you can factor data.

08:26.080 --> 08:30.720
You can, if you've got Chrome open in front of you, you can type these in a console.

08:30.720 --> 08:36.560
So you can either query it from the former timeline, like you can, with many other types

08:36.560 --> 08:42.440
of performance data, or you can register a performance as a driver, and the browser will

08:42.440 --> 08:48.040
fire an event off whenever one of these entries is created.

08:48.040 --> 08:51.360
And this is what we get in a live entry.

08:51.360 --> 08:58.480
And you can see straight away, it's a lot more richer than what we've gone for long tasks.

08:58.480 --> 09:06.120
We can see when the frame started and how long it took to paint it on the screen.

09:06.120 --> 09:11.600
You'll notice the duration here is one and a half seconds, and that's because for this

09:11.600 --> 09:15.200
example, I chose the first long frame on a page.

09:15.200 --> 09:21.600
So it's point-frame, somebody starts to navigate to a page, so it loads URL to the point where

09:21.600 --> 09:27.520
it first starts to play content, and that's normally quite long.

09:27.520 --> 09:32.000
You'll notice there are way more decimal places than we need.

09:32.000 --> 09:35.480
So quite often you can truncate decimal places to remove them.

09:35.480 --> 09:43.640
So we find out, at the highest level, when we try to paint this frame, how long it took.

09:43.640 --> 09:50.000
We can see how long the visitor was blocked, how long they weren't able to interact

09:50.000 --> 09:57.080
for, and blocking duration is basically all the long tasks you take into the long tasks

09:57.080 --> 10:02.360
that were in the frame, you take 50 milliseconds from them, and you add them up.

10:02.360 --> 10:09.160
We can see when the browser actually wanted to start displaying this frame to the visitor.

10:09.160 --> 10:14.880
So we get to understand, OK, this was some work done to create the frame, this is when

10:14.880 --> 10:22.320
we want to do things like styling and rendering and layout, and in that we can begin to understand

10:22.320 --> 10:26.120
our style sheets, our styles flowing down our page.

10:26.520 --> 10:35.560
If the visitor interacts, so tries to click on something tap, while the frame is being presented,

10:35.560 --> 10:39.640
we get a timestamp, so we can tell whether somebody tried to interact with this point.

10:39.640 --> 10:48.200
And lastly, but not least, any script that executes during that frame, that executes

10:48.200 --> 10:56.040
the longer than five milliseconds we get some data on, and we'll dig into that in a moment.

10:56.040 --> 11:02.280
Even just looking at long animation frames on the run without even getting to scripts,

11:02.280 --> 11:07.000
we get some useful information on our visitors' experience.

11:07.000 --> 11:12.120
We can see how many frames we're delaying, so how smooth our visitors' experience is

11:12.120 --> 11:13.840
if they try to interact.

11:13.840 --> 11:17.640
We can get something approximate to a frame rate.

11:17.640 --> 11:23.640
We can see how long of visitors might have to wait when they go to interact.

11:23.720 --> 11:28.120
We can see the worst case for how long it might take for them to get a response.

11:28.120 --> 11:37.200
So we get some good, just general, high-level information on what others experience is.

11:37.200 --> 11:44.040
But the bit I am really most interested in, and I know plenty of other people are as well,

11:44.040 --> 11:48.560
is what they tell us about the scripts, the executes.

11:48.560 --> 12:00.880
And again, contrasting with the long task example, we get a much richer set of data.

12:00.880 --> 12:03.880
We can tell when that script started, the executing.

12:03.880 --> 12:07.480
We can tell how long it executed for.

12:07.480 --> 12:14.520
We can tell whether it's forcing style and layout, so if it's querying the dimensions

12:14.560 --> 12:21.960
and an element on the page, or querying the CSS properties, and forcing the browser

12:21.960 --> 12:28.840
to do a style and layout calculations before it can return that information.

12:28.840 --> 12:31.160
We can actually tell how long it took to pass the script.

12:31.160 --> 12:39.080
The difference between the start time and the execution start is the cost of actually

12:39.080 --> 12:42.040
passing the JavaScript compiling it.

12:42.040 --> 12:49.960
We can see where it gets stock, making synchronous Ajax requests.

12:49.960 --> 12:54.360
So we get a lot of rich information about this script.

12:54.360 --> 12:57.880
We can also tell why the script is executed.

12:57.880 --> 13:02.200
In this case, it was an event listener that was listening to on message.

13:02.200 --> 13:03.520
It could be a click handler.

13:03.520 --> 13:08.040
It could just be a classic script that's embedded in the page.

13:08.040 --> 13:11.960
So we can understand why this script was executed.

13:11.960 --> 13:21.320
And then, lastly, but not least, we can understand what the script it was.

13:21.320 --> 13:28.000
We get the source URL for most scripts, we'll come on to a few exceptions.

13:28.000 --> 13:30.960
We get a source function name, which is the entry point.

13:30.960 --> 13:36.360
So when you think it's the top of the point where you call the script, you can't see what's

13:36.360 --> 13:37.360
underneath.

13:37.360 --> 13:40.600
You can't see the other calls that were made.

13:40.600 --> 13:44.600
There's something called the JS Profiling API that allows you to do that, but I generally

13:44.600 --> 13:45.600
slow data.

13:45.600 --> 13:47.680
But we can see where it was entered.

13:47.680 --> 13:54.200
In this case, the script is modified, so the entry point isn't actually that useful,

13:54.200 --> 13:59.320
but we can tell what's script was responsible for this.

13:59.320 --> 14:07.160
And pages will generate many, many entries.

14:07.160 --> 14:14.920
I tested this page on Chrome with no CPUs throttling, Chrome with four times slow down,

14:14.920 --> 14:17.560
Chrome with six times slow down.

14:17.560 --> 14:25.520
And we get more data, the longer the page is taken to load in this case.

14:25.520 --> 14:29.920
If I use the slower network connection, it would likely change again, because if somebody

14:29.920 --> 14:37.200
set up a timer that's being pulled every 100 milliseconds, the longer it takes that page

14:37.200 --> 14:41.640
load, the more times that time is going to run.

14:41.640 --> 14:45.360
So we get lots and lots of data.

14:45.360 --> 14:51.880
But fortunately, it's really easy to aggregate.

14:51.880 --> 14:54.960
In this case, all ideas aggregated by source URL.

14:54.960 --> 15:00.800
So I can see, while this page is loading, I can see which scripts on the page are taking

15:00.800 --> 15:04.400
the time.

15:04.400 --> 15:09.680
Some of the self-adjusted bundles are taking time.

15:09.680 --> 15:15.760
There's a run product from Dinospace.

15:15.760 --> 15:19.640
There's Google Tag Manager, there's Content Square.

15:19.640 --> 15:28.200
And we can begin to understand which scripts are having the most impact on our visitors

15:28.200 --> 15:32.680
in their own devices.

15:32.680 --> 15:38.120
And it can help us answer these sorts of questions.

15:38.120 --> 15:44.840
And if we can answer these sorts of questions, we can make choices about what we need to do

15:44.840 --> 15:47.640
to improve our visitors experience.

15:48.560 --> 15:59.360
The big question that I think is going to help answer is, we'll give us better information

15:59.360 --> 16:01.640
on third-party tags.

16:01.640 --> 16:06.040
We all think our site is fast, and then somebody from marketing goes and adds a load of

16:06.040 --> 16:09.280
third-party tags and it gets really slow.

16:09.320 --> 16:16.160
It's a classic developer meme, and it's a very mixed picture.

16:16.160 --> 16:18.520
That is true for some sites.

16:18.520 --> 16:24.720
I can show you newspaper publishers where third-party tags are absolutely their problem.

16:24.720 --> 16:31.120
I can show you next-JS built sites, such as Selfridges, where actually next-JS is a framework

16:31.120 --> 16:39.880
if they're problem, and it will allow us to measure this in the wild to understand

16:39.880 --> 16:45.520
what is the cost of frameworks, what is the cost of some of these tags.

16:45.520 --> 16:54.880
And the other thing it can really help with is measuring interactions.

16:54.880 --> 17:01.160
So who's heard of INP or interactions in next-party?

17:01.160 --> 17:07.680
One of the challenges with interactions in next-party is we know somebody's having a slow

17:07.680 --> 17:11.280
interaction, but we don't know why.

17:11.280 --> 17:17.920
And what INP is doing is measuring from the point somebody interacts in the page, in this

17:17.920 --> 17:25.240
case, clicking on the search button on kayak, to the point where the next frame has

17:25.240 --> 17:26.240
presented.

17:26.240 --> 17:32.480
In kayak's case, it's the frame that changes the color of the search button.

17:32.480 --> 17:41.240
So we can kind of measure how smooth somebody's experience is using INP, but we can

17:41.280 --> 17:49.200
tell people, and we do tell people, we can list the elements people interacting with.

17:49.200 --> 17:54.400
So you can see which elements have the worst INP, but at the moment we can't tell them

17:54.400 --> 17:56.400
why.

17:56.400 --> 18:03.320
And there are three phases to INP, there's some interactions, and then we may have

18:03.320 --> 18:08.560
to wait before our event handler runs, because there's something else running on the

18:08.560 --> 18:11.240
browser's main thread.

18:11.240 --> 18:19.640
Then our event handler runs and does whatever work we're aiming to do in response, and

18:19.640 --> 18:27.480
then we present the result of the interaction to the VISTA.

18:27.480 --> 18:31.600
And the way I like to think about it, it's like this.

18:31.600 --> 18:39.080
So input delay is largely beyond our control, whereas what happens in processing time

18:39.080 --> 18:43.120
and presentation delay is about what we do in our event handler and what we're trying

18:43.120 --> 18:46.280
to update the screen to be.

18:46.280 --> 18:51.000
And we can use their tools to debug through interactions, you can go to DevTools, you go

18:51.000 --> 18:57.760
to pause panel, you can start recording, you can click on whatever element you want to interact

18:57.760 --> 19:05.200
with in the page, stop the trace, and it Chrome will give you a view of what happened

19:05.200 --> 19:07.600
during that interaction.

19:07.600 --> 19:17.160
The other task is kind of more problematic, because we don't know what's running when

19:17.160 --> 19:21.040
somebody interacts when I visit this in the wild interact.

19:21.040 --> 19:23.600
It depends when they interact.

19:23.600 --> 19:28.280
So if I load a page and before that page is loaded, I'm trying to open the menu, there

19:28.280 --> 19:32.160
will probably be some scripts running to do with construct in the page.

19:32.160 --> 19:36.120
But we don't know because we can't see.

19:36.120 --> 19:47.120
And what lower and its script attribution allows us to do is begin to identify which scripts

19:47.120 --> 19:50.320
are causing an issue for us.

19:50.320 --> 19:57.200
Here I've just mapped an example of some long animation frame entries, let's say JavaScript

19:57.200 --> 19:58.200
underneath.

19:58.200 --> 20:02.400
And we can match these scripts up to the different phase.

20:02.400 --> 20:10.320
So first of all, we're only interested in long animation frames that finish within our

20:10.320 --> 20:13.920
INP window.

20:13.920 --> 20:20.280
This last lower from the end confused me for a very long time is how could I have another

20:20.280 --> 20:25.080
frame when I haven't shown the current one.

20:25.080 --> 20:32.120
But what happens in a browser is the browser does the work, it does layout styling, it paints,

20:32.120 --> 20:37.840
and then it sends the frame off to the GPU to be painted onto the screen.

20:37.840 --> 20:42.080
And at the point it goes to the GPU, the main thread is free again.

20:42.080 --> 20:47.440
So the main thread can then pick up whatever tasks are next in its queue while it waits

20:47.520 --> 20:53.440
to the GPU present the frame that's just being built.

20:53.440 --> 20:58.960
So because we're only interested in the last finish within our INP window, we can get rid

20:58.960 --> 21:01.280
of that.

21:01.280 --> 21:08.960
And then we need to look at the beginning because in this case, the visitor interacted

21:08.960 --> 21:12.800
while some other script was running.

21:12.800 --> 21:18.600
And this script was running before the interacted.

21:18.600 --> 21:23.840
But we're only interested in the portion that overlaps.

21:23.840 --> 21:32.200
So we can truncated off and just look at these scripts and the portion of the first

21:32.200 --> 21:37.480
script that happened during INP.

21:37.480 --> 21:43.400
And using this, we can map it to the time, using the time stamps, we can map them to

21:43.400 --> 21:44.400
the phase of the INP.

21:44.400 --> 21:50.480
So we can see that in this case, the first four scripts were actually running when

21:50.480 --> 21:52.360
the visitors are trying to interact.

21:52.360 --> 22:00.800
So they slow our interaction down and prior to low-f we had no way of seeing them.

22:00.800 --> 22:06.720
And then we can see this last one, the selfish is up on click.

22:06.720 --> 22:09.760
That's actually our event handler.

22:09.760 --> 22:14.240
And we can see the duration column that that took 12 milliseconds on the rest of it took

22:14.240 --> 22:15.760
about 150 milliseconds.

22:15.760 --> 22:23.480
So they waited for 150 milliseconds before we actually did an R event held around.

22:23.480 --> 22:30.080
They can script-inspire, speech, and help us answer some really good questions.

22:30.080 --> 22:36.000
We can look across all our interactions and see what scripts are affecting them.

22:36.000 --> 22:40.480
Classic case, I'm working with French newspaper.

22:40.480 --> 22:46.520
And they have an on-click handler from Google Tag Manager, and there's also one in their

22:46.520 --> 22:50.600
Facebook script that runs every time somebody clicks on the page.

22:50.600 --> 22:52.800
Anywhere.

22:52.800 --> 22:55.960
And it's part of the common standard behavior.

22:55.960 --> 22:59.080
And that contributes to slow interaction.

22:59.080 --> 23:02.600
But they have no real way of measuring that at the moment.

23:02.600 --> 23:08.480
We can find our slowest interaction handler across the whole page.

23:08.480 --> 23:16.440
We can begin to understand which scripts are having a negative experience.

23:16.440 --> 23:19.920
But there are gaps in the data.

23:19.920 --> 23:24.120
Today there are gaps in the data, there are less gaps in the data than there were six

23:24.120 --> 23:25.120
months ago.

23:25.120 --> 23:29.280
There are still gaps.

23:29.280 --> 23:33.520
As I showed earlier, the entry points might be modified function names.

23:33.520 --> 23:38.240
In this case, they were all empty.

23:38.240 --> 23:44.080
This happens a bit more often than I would like.

23:44.080 --> 23:49.760
It's a particular problem where a script is injected using a tag manager's surprising

23:49.760 --> 23:51.240
enough.

23:51.240 --> 23:55.640
Sometimes we don't get source URLs.

23:55.640 --> 24:02.840
An example I've seen recently is an event handler being injected by GTM.

24:02.840 --> 24:06.760
We don't get the source URL for the script entry.

24:06.760 --> 24:09.120
We don't get a function for it.

24:09.120 --> 24:12.920
If I put the same event handler directly in the page, we get all the data.

24:12.920 --> 24:18.000
But via GTM, we don't.

24:18.000 --> 24:24.680
Some things deliberately do not have script timing entries at the moment.

24:24.680 --> 24:30.240
We don't get any script timing information for extensions because many as a piece of

24:30.240 --> 24:37.120
JavaScript running on a web page has no rights to know what extensions you've been installed.

24:37.120 --> 24:43.080
Garbage collection is another common place where we get long tasks and we don't get any

24:43.080 --> 24:45.440
attribution for them.

24:45.440 --> 24:53.520
I'm hoping that we may get opaque attribution for them.

24:53.520 --> 25:00.400
I don't need to know what script costs are delay or what extension costs are delay,

25:00.400 --> 25:04.560
but it would be good to know that it was an extension in a course of the delay.

25:04.560 --> 25:13.480
If I get some data from the field that says it was an extension that costs this delay,

25:13.520 --> 25:16.000
I can choose not to investigate that any further.

25:16.000 --> 25:21.160
It's something about the business environment that I have no control of.

25:21.160 --> 25:28.080
The other thing to know is timing or what is referred to as a course.

25:28.080 --> 25:36.360
If or when we could time things on the web very accurately, we could use timing attacks

25:36.360 --> 25:41.880
to discover things about visitors and their browsers that we had no rights and no.

25:41.880 --> 25:50.120
In the case of long animation frames, I think they're a course into 8 milliseconds and I think

25:50.120 --> 25:52.920
the scripts are a course and it's about 4 milliseconds.

25:52.920 --> 26:01.240
Just a fuzzy bit added to the script so you can't time things completely accurately.

26:01.240 --> 26:09.680
There's also some slightly weird things about the way dev tools treat interactions.

26:09.680 --> 26:16.680
If you've ever profiled an interaction in dev tools, you should be, you've probably seen

26:16.680 --> 26:24.360
the pointer interaction that's in the yellow bar across the top and it's supposed to represent

26:24.360 --> 26:25.360
ion piece.

26:25.360 --> 26:31.360
We have the front-wester which is input delay, we have the pointer event running which is

26:31.360 --> 26:38.480
processing time and the end-wester is a presentation delay.

26:38.480 --> 26:47.560
I was looking at this data in JSON and couldn't quite follow it so I decided to visualise

26:47.560 --> 26:58.560
it and one of the things Chrome does and webvitals.js does this as part of its attribution

26:58.560 --> 27:08.160
is if or the event handle has run in the same frame than it merges them together from a

27:08.160 --> 27:09.680
timing point of view.

27:09.680 --> 27:16.120
It starts input delay when the VISTA is interacted.

27:16.120 --> 27:23.360
It starts processing time at the first processing time for the events.

27:23.360 --> 27:31.040
In this case it's that top blue line which is the pointer down event and then it carries

27:31.040 --> 27:39.800
on measuring processing time until the last, until the latest end point for processing

27:39.800 --> 27:47.240
time for all the event handle is so in this case it's the click which is in the middle

27:47.240 --> 27:56.640
row and they merge them together and in this case there's a point of down, there's a

27:56.640 --> 28:02.320
point up, there's a touch start, there's probably a touch end and there's a click.

28:02.320 --> 28:10.320
There's some validity for merging them together but when we map the event handle

28:10.320 --> 28:21.360
is mapping a touch start to processing time seems a reasonable thing to do.

28:21.360 --> 28:29.560
My only challenge is that if you do the same interaction but your timing isn't quite the

28:29.560 --> 28:37.000
same then the event handle is an event timing information gets split across multiple

28:37.000 --> 28:39.000
fronts.

28:39.000 --> 28:47.880
The difference between this devsource trace and the previous one is I held my finger on the

28:47.880 --> 28:56.880
menu icon for an infinitesimal tiny little bit longer of time but what we can see is

28:56.880 --> 29:07.000
that our interactions have been split across three phones.

29:07.000 --> 29:15.160
In the previous one touch start would be associated with processing time and this one

29:15.160 --> 29:25.040
touch start is associated with input delay for the click event so I'm not completely convinced

29:25.040 --> 29:30.160
about Chrome's approach to this.

29:30.160 --> 29:32.440
This stuff took me a while to figure out.

29:32.440 --> 29:41.080
To me quite a few weeks of looking at this API to understand what was going on initially

29:41.080 --> 29:43.520
I tried visualizing the data.

29:43.520 --> 29:52.000
Get a punch Jason, convert it into SVG, put it on a page and you get a chart that looks like

29:52.000 --> 29:53.000
this.

29:53.000 --> 30:00.440
In this case the yellow lines are the long animation frames the pink is the script execution.

30:00.440 --> 30:07.760
I quickly ran into problems with this because although I could tell the long animation frames

30:07.840 --> 30:08.760
how long they were.

30:08.760 --> 30:10.840
I could see the script running within them.

30:10.840 --> 30:13.120
This is the view I'm used to.

30:13.120 --> 30:20.720
I couldn't match the visualization to what I was used to seeing on the main thread.

30:20.720 --> 30:29.480
Couldn't match it up to these core stacks of JavaScript functions so it became quite hard

30:29.480 --> 30:31.480
for me to understand what's going on.

30:31.480 --> 30:40.680
And around this time the Chrome DevSource team had a call me about something related and

30:40.680 --> 30:50.800
they said, oh, if you tried this API and with this API what we can do is we can annotate

30:50.800 --> 30:51.800
the DevSource timeline.

30:51.800 --> 30:54.440
We can add our own data to it.

30:54.440 --> 30:58.000
So I create an extension in this case.

30:58.080 --> 31:03.360
This is the long animation frames, creates a performance measure and that performance measure

31:03.360 --> 31:08.960
is displayed as one of those blocks in the DevTools timeline.

31:08.960 --> 31:11.960
Looks like this.

31:11.960 --> 31:22.040
And immediately I was able to start to understand how the lower fentry is lined up with

31:22.080 --> 31:31.160
the main thread work, how the scripts themselves lined up with or the script attribution

31:31.160 --> 31:36.640
lined up with the scripts on the main thread and could also get to see things like

31:36.640 --> 31:42.600
how much rendering, how much time we're spending in style and layout calculations, which

31:42.600 --> 31:46.480
is quite a lot.

31:46.480 --> 31:50.760
The extensions there, if anybody wants to play with it, you have to load it as an unpack

31:50.800 --> 31:59.200
extension, but it allows you to start visualizing love for yourself.

31:59.200 --> 32:10.040
And within half a day of actually starting to use it, I actually found some Chromebooks.

32:10.040 --> 32:20.440
So it's a lot to be said in starting to visualize data in familiar places and familiar tools.

32:21.000 --> 32:29.880
And this case, lower scripts, lower wasn't picking up scripts with from promised

32:29.880 --> 32:32.760
handles being resolved.

32:32.760 --> 32:38.840
So fans of bugs got it fixed, got the API improved.

32:38.840 --> 32:44.760
And Kisham guessed it, I really like the animation frames, I like the fact we are going

32:44.760 --> 32:52.760
to get to a point where we can see the impact of our scripts in our visitors'

32:52.760 --> 32:56.760
browsers and what impact they're having on their experience.

32:56.760 --> 33:01.880
We get a real insight into the code we're shipping and how it runs and how it varies

33:01.880 --> 33:06.400
for different people in different places on different devices.

33:07.360 --> 33:15.040
I'm working with a customer at the moment and they track large contentful paint.

33:15.040 --> 33:22.240
And depending on where they run their advertising campaigns, large contentful paint changes.

33:22.240 --> 33:29.360
There, I can always tell when they've run a marketing campaign targeting the UAE,

33:29.440 --> 33:36.080
because in the UAE network connectivity is not great and everybody uses

33:37.120 --> 33:41.840
low-ish cost Android phones and often a web view.

33:41.840 --> 33:48.160
And they're shipping lots of JavaScript, but they have no idea of what that JavaScript is costing

33:48.160 --> 33:56.480
them in market terms in the UAE. So it will give us an insight into the runtime costs of the

33:56.480 --> 34:01.680
JavaScript we ship and start allowing us to identify the problem scripts because we can have

34:01.680 --> 34:06.560
conversations about them, we can have conversations about should we carry on using this framework,

34:06.560 --> 34:12.720
we can have conversations with our marketing people about no this marketing tag really is causing

34:12.720 --> 34:20.240
our visitors a problem and damaging their overall experience.

34:20.560 --> 34:26.960
I kind of feel like I've just scratched the surface a little bit when you're looking at this

34:26.960 --> 34:33.680
deeply. I think beyond just looking at script timing, it's quite a lot else

34:33.680 --> 34:41.440
that love can tell us. We can start perhaps to understand what work the browser's

34:41.440 --> 34:48.480
having to do before it presents that first set of initial content to a visitor so first

34:48.480 --> 34:53.680
contentful paint or where the scripts are delaying our large content for paint.

34:56.080 --> 35:01.440
I mentioned it on one of the earlier slides, but how much time was spending

35:02.400 --> 35:09.920
doing layout and styling is largely invisible at the moment. Where we have scripts that

35:09.920 --> 35:17.600
say injector style sheet and causes the whole page to be re-styled. We don't see that.

35:18.640 --> 35:25.360
We can kind of see what the overhead of script compilation will be and how much synchronous work

35:26.160 --> 35:33.280
our scripts are doing. So although I focused on looking at what the straightforward

35:34.240 --> 35:42.240
impact of script execution is, I think this API has a lot more to tell us. If you want to

35:42.240 --> 35:52.400
dig into it further, the W3C spec is a bit dry reading that covers it in detail,

35:52.400 --> 35:59.600
NDN has a good article on it and of course this stuff on Chrome developers. There's a copy of

35:59.680 --> 36:07.360
these slides that are already uploaded onto the phos then page, but you can either ask me

36:07.920 --> 36:22.160
any questions now or if you have any questions later on you can find me on Blizz Gay. Thank you.

