My Problem

I’m working on an application to view at least 40,000 media files. I was surprised when I first put 40k files in the view container. Scrolling was as smooth as if I had 400 files. Or 40. Chrome was great when an element had 40k children.

Then I tried to do things other than view them all

  • zoom
  • filter
  • search
  • sort

Every time I “fixed” a flash, stutter, delay or other issues, another problem would show up somewhere else. I ended up with a fairly complex implementation to add, remove, remove, or change style to do the minimal DOM changes for a user action such as sort. There were still occasional flashes and the code was not maintainable.

The Solution

In the screenshot below, I have

But the view element only has 6 children with images, not 26k or 40k. There is a 7th child.

 <div class="view layout">
    <div class="media-item"...><img src="/thumbnail/38676"></div>
    <div class="media-item"...><img src="/thumbnail/467" ></div>
    <div class="media-item"...><img src="/thumbnail/944" ></div>
    <div class="media-item"...><img src="/thumbnail/1553" ></div>
    <div class="media-item"...><img src="/thumbnail/1056" ></div>
    <div class="media-item"...><img src="/thumbnail/856" ></div>
    <div style="position: absolute; top: 380601px;..."></div>
</div>    

The 7th child is absolute-positioned where the 26605th item would be. That creates a scrollHeight which allows the user to scroll to the last time.

As the user scrolls, my scroll event handler replaces the view element’s children with the images the user scrolled to. It worked pretty well. The code was much more maintainable. But there were still occasional flashes. Various combinations of Element.remove(), Element.append(), Node.removeChild(), and node.appendChild() didn’t work. I could still make the view flash as I scrolled or sorted or did other operations. Element.append() even takes multiple arguments which are all appended in one call but I still had to remove elements in another function.

Then I found Element.replaceChildren(). I had never noticed it before. But it solved my problems. It doesn’t matter If I replace all of the children, or some of them, or reorder them.

I create an array, layoutChildren, with the Elements I want in the view. And pass those elements to Element.replace() of my view Element.

view.replaceChildren(...layoutChildren);

Summary

One of the great things about the DOM is that it does A LOT of things very efficiently.

The downside is that it does so much that it’s hard to know or remember all of the capabilities that are there for edge cases since 99% of what we need is done so well with a few simple functions.