Practical Problem Solving with Algorithms

Optimizing DOM Traversal

Kyle Simpson

Kyle Simpson

You Don't Know JS
Practical Problem Solving with Algorithms

Check out a free preview of the full Practical Problem Solving with Algorithms course

The "Optimizing DOM Traversal" Lesson is part of the full, Practical Problem Solving with Algorithms course featured in this preview video. Here's what you'd learn in this lesson:

Kyle optimizes the diagonal tile algorithm by reducing DOM traversals and saving a tile's row and column indices to dataset properties. Use the option-1 branch linked below as a starting point for this lesson.


Transcript from the "Optimizing DOM Traversal" Lesson

>> Let's observe a few things about our current approach. Let's see if there's any low-hanging fruit, any paper cuts that we could easily eliminate. For me the one that jumps out the most, and maybe it's just because I've made this mistake many, many times. But every time I click the highlight, I requery the DOM for the list of 64 tile elements.

You see that, that is something that never changes. Once we draw the board that is fixed, but every single time I clicked on it, I am re computing the answer to that question, that's unnecessary work. To me that's the lowest hanging of the fruit here. There's other things that others might have changed first.

That's the first thing I wanna change, is I don't wanna recompute that every time I wanna save that work. So instead of the original board element, I'm just going to maintain an array of the tiles. It has that DOM element so it's not a real native array but I'm just gonna maintain that list.

So instead of saving off this reference to original board element here's what I'm gonna do. I'm gonna set this right here, right after I've drawn the board I'm gonna do it once and save it. Now I know I'm using the vehicle of DOM API calls that almost none of you ever worked with any more because of frameworks.

I know we're using that as the vehicle here and it may feel like this system Old School are out of touch but I don't want you to worry about the DOM API usage nearly as much as I want you to think about when is work being done and how often is it being done.

DOM work is one of those things that is exceptionally costly, cuz the DOM is still always the slowest part of our JavaScript times. And so it's a way for me to illustrate the problem here. But it's really about when that work gets done and how often it gets done.

Why not do it once upfront and remember that information instead of waiting until much later to do it. Does it makes sense? There's one other little change that because we don't have this original board EL. We're not gonna be able to do that one, and so we're gonna need to do, let board EL and get that from row EL.

And then we're gonna put in board EL here. All right, let's talk about this findtile function. Let's think about yet another different way that we could have done it, maybe not better but a different way that we could have done it. Instead of relying upon the built-in ones or the built-in node list maybe what we do, because we now have that tiles array, maybe we just simply loop over the tiles array and use the indexing to find the element within that tiles array.

So if I were to loop over this tiles array, I'm gonna get an element that I could ask it, what is your index? And I could compare that index to the index that I'm looking for. And if I found the right one, I could return it. Did I lose you or did that make sense?

Remember how we computed the index of any given element? We did it just right here. This was computing the row and column index for any element. So we could copy that logic down into here or even put it into its own function to recompute an element's index and ask it if its computed index is the same as the one that we're looking for.

That's a way of doing this. But that's a big old waste of time to recompute the index over and over again because I already know the index. When do I know the index? When I'm constructing the board, that's information that I know at this moment and then I throw it away.

And I recompute it later, over and over and over again. What if we saved the information of what each tile elements row and column index coordinate is with the tile element? You follow that, don't throw the work away, save the work, that's an algorithm in this best friend.

Now how are we going to save a piece of information with a DOM element? It turns out another part of the native DOM API's that many of you have not been exposed to Is what we call dataset. It's a special mechanism for associating data with a dom element.

There is a gigantic caveat that you need to pay attention to so don't miss this. The only data that you can associate with a DOM element in this way, through the data set, is string information. If you try to save a number, guess what's going to happen to the number?

It's going to get turned into a string and that will create a gotcha for us later. But we'll deal with that when we get to it, okay? So we can store information with an element in its data set question.
>> It's just a personal note. If you can use a set and then pass in the element and then you can associate any arbitrary data with an element.

>> You're talking about map?
>> Yeah.
>> Yes.
>> Or sorry, map.set.
>> We can use the dom element as a key in the map, absolutely.
>> Yeah, map.set, I mean.
>> Yes, we absolutely could do that. We're not going to do that this time, but we absolutely could construct another data structure M map, remember I talked about it at the beginning of the course.

What is a map? A map is a hash map, meaning any object can be a key including a DOM element. And then within the map, if we save as the key a DOM element, we can save whatever values we want. Right now, we're gonna take a much more narrow approach, which is the data set.

And the builtin HTML5 data set capability, it can only store stuff as strings. And if you want a mental model for why it can only do strings, it's because it represents it as attributes on the DOM element. And we know that attributes can only be string values, so that's your mental model.

It's literally like serializing it as if it's an attribute on the element. But nevertheless, that's still gonna work okay for us. So that's what we're gonna do is we're gonna say tileelement.dataset.row is equal to i. And, this j. So I've created two dataset properties row and column.

They are gonna have the values i and j respectively. But note the caveat that it will have turned those into strings, even though we assigned it numbers. So you cannot assign it a function or some complex circularly nested object or anything like that, that's gonna fail because it can't be stratified properly.

So we can now use that information, can't we? As we loop over our tiles, all we need to do is say if el.dataset.row is equal to row and el.dataset.column is equal to column, return el. I wonder if anybody spots but rather important large caveat here in line 64.

Maybe I'll make it super explicit and put the cursor here. What would happen if I wrote the code like that the way so many people write their JavaScript?
>> The type of the diffference?
>> It would fail, because we're passing in numbers and the thing that's in data set has been turned to a string.

So you can either cast it back to a number or you can do as I do, and let JavaScript coercion mechanism take care of that implementation detail for us. And if your linter yells at you just turn your linter off. Again, I'm not saying that this is the right way for fine tile to be written indeed, we're eventually gonna refactor it so there is no fine tile function.

I'm just simply showing you different ways of approaching this and letting you see the trade-offs, the good and the bad in different ways of doing things. Let's do a little regression test. Let's switch over to our browser, refresh, and make sure that it's still working. It's not an automated test, but it still appears to be working correctly even for the quite literal corner cases pun intended.

Y'all must be too asleep. It must be like the post lunch. What is he talking about, chessboards? Even my good jokes nobody laughs that well, maybe they're just not good jokes, I don't know. This code represents the option two branch. If your code happens to not be working, you miss something less than equals somewhere, don't feel bad, stash your changes check out the option to branch.

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