Let's say we have a code that injects series of similar elements into the DOM. Something like this:
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 snippet is run in Firefox (25.0), the time between calling 'inject' and actually seeing its results more-o-less corresponds to what is logged by time/timeEnd
. For 1000 elements, about 4 ms; for 10000, about 40 and so on. Quite normal, ain't it?
It's very not so, however, with Chrome (30.0 and Canary 32.0 are tested). While the reported time for processing and appending is actually less than Firefox's, rendering of these elements takes a LOT more.
Puzzled, I've checked the Chrome's profiler for different scenarios - and it turned out the bottleneck is in Recalculate Style action. It takes 2-3 seconds for 10000 nodes, 8 seconds for 20000 nodes, and whopping 17 seconds for 30000 nodes.
Now the real question is: has anyone been in the same situation, are there any workarounds?
One possible way we've thought about is limiting the visibility of these nodes in a sort of lazy load ('a sort of', because it's more about 'lazy showing': the elements will already be in place, only their visibility will be limited). It's confirmed that 'Recalculate Style' is triggered only when element is about to become visible (which makes sense, actually).
Looks like the trouble is with the li
elements that have display:list-item
If instead of ul
/li
you use div
elements it works pretty fast in chrome..
Also creating a css rule of li{display:block;}
fixes the delay.
And manually adding the list-item
shows the delay even if the elements are already rendered in the DOM (they have to be re-rendered ofcourse)
See demo at http://jsfiddle.net/6D7sM/1/
(so it seems that chrome is slow in rendering display:list-item
elements)
There is also a relevant bug submission to chrome http://code.google.com/p/chromium/issues/detail?id=71305 which has been merged into http://code.google.com/p/chromium/issues/detail?id=%2094248 (looks like in earlier versions it was crashing chrome, but it has been fixed. the crashing, not the speed)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With