Performance with infinite scroll or a lot of dom elements?

JavascriptPerformanceDom

Javascript Problem Overview


I have a question on a big # of dom elmenets and performance.

Let's say I have 6000 dom elements on a page and the number of the elements can be increased as a user interact with the page (user scrolls to create a new dom element) like twitter.

To improve the performance of the page, I can think of only two things.

  1. set display to none to invisible items to avoid reflow
  2. remove invisible items from the dom then re-add them as needed.

Are they any other ways of improving a page with a lot of dom elements?

Javascript Solutions


Solution 1 - Javascript

We had to deal with a similar problem on FoldingText. As the document grew larger, more line elements and associated span elements were created. The browser engine just seemed to choke, and so a better solution needed to be found.

Here's what we did, may or may not be useful for your purposes:

Visualize the entire page as a long document, and the browser viewport as the lens for a specific part of the long document. You really only have to show the part within the lens.

So the first part is to calculate the visible view port. (This depends on how your elements are placed, absolute / fixed / default)
var top = document.scrollTop;
var width = window.innerWidth;
var height = window.innerHeight;

Some more resources to find a more cross-browser based viewport:

https://stackoverflow.com/questions/1248081/get-the-browser-viewport-dimensions-with-javascript

https://stackoverflow.com/questions/871399/cross-browser-method-for-detecting-the-scrolltop-of-the-browser-window

Second, you need a data structure to know which elements are visible in that area

We already had a balanced binary search tree in place for text editing, so we extended it to manage line heights too, so this part for us was relatively easy. I don't think you'll need a complex data structure for managing your element heights; a simple array or object might do fine. Just make sure you can query heights and dimensions easily on it. Now, how would you get the height data for all your elements. A very simple (but computationally expensive for large amounts of elements!)

var boundingRect = element.getBoundingClientRect()

I'm talking in terms of pure javascript, but if you're using jQuery $.offset, $.position, and methods listed here would be quite helpful.

Again, using a data structure is important only as a cache, but if you want, you could do it on the fly (though as I've stated these operations are expensive). Also, beware of changing css styles and calling these methods. These functions force redraw, so you'll see a performance issue.

Lastly, just replace the elements offscreen with a single, say <div> element with calculated height
  • Now, you have heights for all the elements stored in your Data structure, query all the elements that lie before the visible viewport.

  • Create a <div> with css height set (in pixels) to the sum of the element heights

  • Mark it with a class name so that you know its a filler div

  • Remove all the elements from the dom that this div covers

  • insert this newly created div instead

Repeat for elements that lie after the visible viewport.

Look for scroll and resize events. On each scroll, you will need to go back to your data structure, remove the filler divs, create elements that were previously removed from screen, and accordingly add new filler divs.

:) It's a long, complex method, but for large documents it increased our performance by a large margin.

tl;dr

I'm not sure I explained it properly, but the gist of this method is:

  • Know the vertical dimensions of your elements
  • Know the scrolled view port
  • Represent all off-screen elements with a single div (height equal to the sum of all element heights it covers for)
  • You will need two divs in total at any given time, one for elements above the visible viewport, one for elements below.
  • Keep track of the view port by listening for scroll and resize events. Recreate the divs and visible elements accordingly

Hope this helps.

Solution 2 - Javascript

No experience myself with this, but there are some great tips here: http://engineering.linkedin.com/linkedin-ipad-5-techniques-smooth-infinite-scrolling-html5

I had a look at Facebook and they don't seem to do anything in particular on Firefox. As you scroll down, the DOM elements at the top of the page don't change. Firefox's memory usage climbs to about 500 meg before Facebook doesn't allow you to scroll further.

Twitter appears to be the same as Facebook.

Google Maps is a different story - map tiles out of view are removed from the DOM (although not immediately).

Solution 3 - Javascript

It's 2019. The question is really old, but I think it is still relevant and interesting and maybe something changed as of today, as we all now also tend to use React JS.

I noticed that Facebook's timeline seems to use clusters of content which is hidden with display: none !important as soon as the cluster goes out of view, so all the previously rendered elements of the DOM are kept in the DOM, it's just that those out of view are hidden with display: none !important. Also, the overall height of the hidden cluster is set to the parent div of the hidden cluster.

Here are some screenshots I've made:

enter image description here

enter image description here

enter image description here

As of 2019, what do you think about this approach? Also, for those who use React, how could it be implemented in React? It would be great to receive your opinions and thoughts regarding this tricky topic.

Thank you for the attention!

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMoonView Question on Stackoverflow
Solution 1 - JavascriptMutahhirView Answer on Stackoverflow
Solution 2 - JavascriptcbpView Answer on Stackoverflow
Solution 3 - JavascripttonixView Answer on Stackoverflow