I’m trying to find an efficient algorithm for dynamically loading background-images for a bunch of <li>‘s, and are having some efficiency problems. My current code looks like this:
function elementInView($elem, vps, vpe) {
var elempos = $elem.position();
var pagestart = elempos.top + vps;
var pageend = elempos.top + vps + $elem.height();
var offset = 78 - Math.max(0,vps-pagestart) - Math.max(0,pageend-vpe);
// I want to update all items that are within 200 pixels of
// the current viewport
return (vpe > 0 && offset > -200);
}
$('#container').bind('scroll', function() {
var $container = $(this);
var vps = $container.scrollTop();
var vpe = vps + $container.height();
$('li:not(.bgset)', '#container').each(function() {
var $this = $(this);
if (elementInView($this,vps,vpe)) {
$this.addClass('.bgset');
// Set the background-image (doesn't affect performance noticably.)
}
});
});
This takes between 200-600 ms on a list with ~250 items, and ~1500 ms for a list with ~1500 items, which makes it pretty much unusable.
Can anyone see any problems with this, or is this basically the best way to do this? I’ve tried getting ALL <li>‘s instead of $('li:not(.bgset)', but that didn’t really have any impact at all.
(The list contains dynamically generated background-images (which doesn’t get cached AND get’s changed quite a lot), and loading around ~1500 of them really slowed everything down, which is why I tried this approach)
EDIT: Forgot to mention, I’ve thought about writing a custom jQuery-selector which matches the elements that return true for elementInView, would this be a better approach?
The DOM is slow. To get raw speed, you need to use innerHTML.
To avoid string manipulations, you may consider a JS templating engine, there are plenty of them.
We’ve built the templating engine PURE, as it is tiny and fast, it works very well to build pages for mobiles.
Another option could be to consider the problem upstream. Are you sure you want to provide your user a list of hundreds/thousands of items?