Let's say we have code that introduces a number of similar elements into the DOM. Something like that:
var COUNT = 10000, elements = Object.keys(Array(COUNT).join('|').split('|')); var d = document, root = d.getElementById('root'); function inject() { var count = COUNT, ul = d.createElement('ul'), liTmpl = d.createElement('li'), liEl = null; console.time('Processing elements'); while (count--) { liEl = liTmpl.cloneNode(false); liEl.textContent = elements[count]; ul.appendChild(liEl); } console.timeEnd('Processing elements'); console.time('Appending into DOM'); root.appendChild(ul); console.timeEnd('Appending into DOM'); }; d.getElementById('inject').addEventListener('click', inject);
Demo
When this fragment runs in Firefox (25.0), the time between the call to 'inject' and the actual viewing of its results more or less corresponds to the fact that time/timeEnd . For 1000 elements, about 4 ms; for 10,000, about 40 and so on. That’s fine, right?
This is very different, however, with Chrome (30.0 and Canary 32.0 tested). Although the time to process and add is actually shorter than that of Firefox, rendering these items takes more LOT.
Surprised, I checked the Chrome profiler for different scenarios - and it turned out that the "Recalculate Style" action was a bottleneck. It takes 2-3 seconds for 10,000 nodes, 8 seconds for 20,000 nodes, and as much as 17 seconds for 30,000 nodes.
Now the real question is: has anyone been in the same situation, are there any workarounds?
One of the possible ways that we were thinking about is to limit the visibility of these nodes in the form of lazy loading ("sort of" because it is more about a "lazy display": the elements will already be in place, only their visibility will be limited). He confirmed that "Recalculate Style" only starts when the element becomes visible (which makes sense, actually).