patternjavascriptMinor
Loading visible images
Viewed 0 times
imagesvisibleloading
Problem
I am using this code to get images to load only if they are visible. However, it seems to be slow with thousands of images, even if they are not rendered.
I am using this code to render images:
Everything works, but how can I optimize it?
function getViewportHeight() {
if(window.innerHeight) {
return window.innerHeight;
}
else if(document.body && document.body.offsetHeight) {
return document.body.offsetHeight;
}
else {
return 0;
}
}
function inView(elem, nearThreshold) {
var viewportHeight = getViewportHeight();
var scrollTop = (document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop);
var elemTop = elem.offset().top;
var elemHeight = elem.height();
nearThreshold = nearThreshold || 0;
if((scrollTop + viewportHeight + nearThreshold) > (elemTop + elemHeight)) {
return true;
}
return false;
}
function loadVisibleImages() {
jQuery('img[data-src]').each(function() {
if(jQuery(this).is(':visible')) {
if(inView(jQuery(this), 100)) {
this.src = jQuery(this).attr('data-src');
}
}
});
}
jQuery(window).scroll(function() {
loadVisibleImages();
});I am using this code to render images:
Everything works, but how can I optimize it?
Solution
Here are a few callouts/suggestions:
You should throttle your code on the
You probably don't need to get the viewport size every time through the loop. This should be called once at the start and then only on the
You can add a class to all the images that have already been processed and exclude them from your selector. This way you are only dealing with new images.
For example:
If you haven't already you should wrap your code in an IIFE so you can create a private scope. Just take the code below and put it around your existing code. This would also allow you to use
You could optimize the loop in your
Hope that helps!
You should throttle your code on the
scroll event. That way the event doesn't fire thousands of times. You can read up this article for more information. A basic example would be: //which makes the `scroll` event fire every 250ms.
$(window).scroll( $.throttle( 250, loadVisibleImages) );You probably don't need to get the viewport size every time through the loop. This should be called once at the start and then only on the
resize event. Otherwise, it never changes so there is no need to re-calculate it.//which makes the `resize` event fire every 250ms.
$(window).resize( $.throttle( 250, getViewportHeight) );You can add a class to all the images that have already been processed and exclude them from your selector. This way you are only dealing with new images.
For example:
function loadVisibleImages() {
jQuery('img[data-src]').not('.processed').each(function() {
if(jQuery(this).is(':visible')) {
if(inView(jQuery(this), 100)) {
this.src = jQuery(this).attr('data-src').addClass('processed');
}
}
});
}If you haven't already you should wrap your code in an IIFE so you can create a private scope. Just take the code below and put it around your existing code. This would also allow you to use
$ for jQuery without worry.(function( $ ) {
//your code here
}) ( jQuery );You could optimize the loop in your
loadVisibleImages functions. See your other question.Hope that helps!
Code Snippets
//which makes the `scroll` event fire every 250ms.
$(window).scroll( $.throttle( 250, loadVisibleImages) );//which makes the `resize` event fire every 250ms.
$(window).resize( $.throttle( 250, getViewportHeight) );function loadVisibleImages() {
jQuery('img[data-src]').not('.processed').each(function() {
if(jQuery(this).is(':visible')) {
if(inView(jQuery(this), 100)) {
this.src = jQuery(this).attr('data-src').addClass('processed');
}
}
});
}(function( $ ) {
//your code here
}) ( jQuery );Context
StackExchange Code Review Q#90150, answer score: 3
Revisions (0)
No revisions yet.