Introduction to Dev Tools, v3

Layout Thrashing Solution

Jon Kuperman

Jon Kuperman

Cloudflare
Introduction to Dev Tools, v3

Check out a free preview of the full Introduction to Dev Tools, v3 course

The "Layout Thrashing Solution" Lesson is part of the full, Introduction to Dev Tools, v3 course featured in this preview video. Here's what you'd learn in this lesson:

Jon live codes the solution to the Layout Thrashing exercise and answers a student's question about viewing the call stack.

Preview
Close

Transcript from the "Layout Thrashing Solution" Lesson

[00:00:00]
>> So we already kind of looked at what it looks like on normal. So let's add, I think for me, it's adding 400 or maybe 500, I start seeing some really significant jank. So I'll do the recording for one second, again, always recommend keep the recordings as small as possible cuz there's just so much data.

[00:00:17]
But it's really cool, so, hopefully this should look very different this time, with all of that stuff, than it did the last time. And there's a couple of things I wanna draw your attention to one, is the red lines across the top, in the frames per second. So, those red lines are where it lost a frame, right?

[00:00:32]
Or it dropped a frame, so, it should be really obvious when you load up a worksite or something like that, get it in that state where you're worried about it, do a recording. And you should see, Chrome is like telling you hey, there was some serious issues here.

[00:00:46]
In a very similar vein, under the experience panel here, you see this layout shift in red, which I'm not 100% sure on what it means, but it definitely relates to the frame dropping in some ways. Something's going on there, another thing that you can see is that whereas before, the chart here for the CPU was mostly small mountains with a lot of free time, though white and gray slashes.

[00:01:12]
And now it's basically 100% CPU for the entire time it's running the app. You can still see it kind of comes in these waves, there's little bounces, but it's just a massive amount. So if we go ahead and we expand the main tab, we can kind of see every app has its own very unique personality, right with how things are working.

[00:01:35]
And so you can kind of see here that what keeps happening is every 100 milliseconds some tasks is getting fired, and something is going on that's causing again, you can see more red saying that the task took too long. There's probably jank or whatever. When you're looking at the thread, what you don't care about is how tall things are.

[00:01:57]
That's fine because that's complexity of your code is all it is. So if you have, my example with debugging where you have function one calls, function two calls, function three, let's say you just had 100 of those, you would have a really long execution stack, but it would happen really quickly cuz all it's doing is calling another function.

[00:02:15]
So when you're looking at this thing, if it goes up and down 100 or something like that, that's nothing to worry about. What you do wanna worry about is the ones that are too wide, because as we said before, every 16 milliseconds it needs to have a new frame to send basically.

[00:02:31]
And so you're looking for long wide ones or the problematic ones and the really long call stacks are not a problem. And so you can see here, we only had 16 milliseconds to produce this frame. And this animation itself took 129 milliseconds so that is a lot of drop frames happening there.

[00:02:50]
In a similar way, the way that you can find the problematic function or the problematic code is to go down the call stack and find the last long one before they get really small. So if you think about it, it's if you have a if you have a function called Fibonacci, and it takes forever to generate a Fibonacci number.

[00:03:10]
And you wrap it in a function called foo, and all foo does is call Fibonacci, foo will look long too even though it's not really doing anything cuz it's the parent of a long function, right? And so you'd see foo Fibonacci but what so you wanna do is you wanna keep looking at the long ones until you get to the last long one who itself only called a bunch of short ones, because the short ones, aren't gonna be a problem.

[00:03:34]
And then you know the last long one is going to be the closest that you can get to the problematic function. Does that make sense, I know that it's kind of a confused, so in this example, we see that the task took too long. And we wanna know what caused and so we can see this is long, long, long then we get to App update long.

[00:03:51]
And then after app update, if we were to zoom in here, we would just see that it's calling a million tiny any little short ones. So, if we wanted to know what function was the problem here, app update is the last long one before a bunch of the short ones.

[00:04:06]
And then you can do cool things, so you can click on app update if we wanted to kinda see what's going on. And we can bring back up this summary view here, once we click on any cell you can see this is changing. So we can click on the last long one and then we can go and open the actual file where the function got called boom here.

[00:04:25]
So again, from the performance, you find whichever cell that you wanna investigate, and then you look at the summary, which you might have to drag up a little bit and then you click on the file name. So one thing that you'll notice that's really cool is after you've done a performance audit, when you look into sources, Chrome will save how long the function took to run in the sidebar here, of all the stuff that it was able to see.

[00:04:48]
Which is really cool, so you can see this app update took a super long time, took like well over a second, almost 1.5 seconds. And then as you start looking into it, so that basically gets us to the JavaScript code that's causing our problem. In this case, we can see that it's doing a lot of reads and writes right, where it's going through each one of these little Chrome Dev Tools things and it's looking to see so it's reading them to see if it has a class name.

[00:05:16]
And then if it does have that class name, it's reading them again to get the offset from it. And then it's reading the current position against the max height of the screen that it's in. So it's doing really, really heavy calculation right and it's doing them in an inefficient order where it's like read, write, read, write, read, write, just like we saw before.

[00:05:35]
And what's really cool is that there's this optimize button on here and literally all this is doing is it's batching those things so that they're done without invalidating layout just like we were talking about in the example before. And so even with this many hundreds and hundreds of them, if you click optimize, you can see that they instantly smooth right up.

[00:05:54]
So it's not just don't do heavy lifting, the web is very capable of doing heavy lifting. But it's important to know how these layouts happen because if you optimize around them, like do all your reads and then do all your rights, and you put both of those in request animation frame you can get a really smooth animation even though it's still doing a lot of really heavy work.

[00:06:13]
How are folks feeling about that? Any questions?
>> You said something about getting the opportunity to dig into the call stack. So, cuz when we clicked on thrashing.js that did take us to sources.
>> Right.
>> But there was nothing in the call stack on the right. So, I think I'm missing a piece of the puzzle.

[00:06:32]
>> Yeah, no, absolutely, no, that's great. So yeah, the question was about that I mentioned earlier that when we're looking at performance, we'll be able to look into the call stack of how it got there. But when you clicked on one like we did, and you clicked on the link, which is what we had done earlier, it didn't actually take you to sources with a call stack, right?

[00:06:52]
We got to App update and we clicked on this and it was not paused at a debugger. So we've got two options here, option one is we can now that we've gone to sources, we can set a debugger, right? We can set a breakpoint there and then let it hit again and when it hits again, we'll get the full call stack over here.

[00:07:08]
So that's option one, option two is back over here on this performance panel, where we can actually see where these things came from, this one's not a good example because it's literally just animation frames are firing. Every time, but If this was wrapped in a function or something that you would still see the call stack here as well.

[00:07:30]
So it's kinda up to you if you just want to peek at it, the call tree can be really good for that if you just wanna see where it came from. If you really wanna understand it better then I would recommend clicking on the file name and then adding app update is here, so then adding one here and then you're able to see.

[00:07:46]
But again, this example is not great for that because it's just request Animation Frame firing. But if you did have something calling other stuff like react generating, you will see that all here in the call stack.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now