Skip to content

Instantly share code, notes, and snippets.

@CSElliyas
Created August 31, 2019 07:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CSElliyas/3e8e13a87964f7e884370ea0cb2b18fd to your computer and use it in GitHub Desktop.
Save CSElliyas/3e8e13a87964f7e884370ea0cb2b18fd to your computer and use it in GitHub Desktop.
// generic throttle function
function throttle(func, wait) {
var timeout;
return function() {
var context = this, args = arguments;
if(!timeout) {
timeout = setTimeout(function() {
timeout = null;
}, wait);
func.apply(context, args);
}
};
}
function isFunction(variable) {
return variable && {}.toString.call(variable) === '[object Function]';
}
// naive function for seeing if element is visible in user's viewport
function isElementInViewport(element) {
var elementBounds = element.getBoundingClientRect();
return window.innerHeight > elementBounds.top
&& 0 < elementBounds.bottom
&& window.innerWidth > elementBounds.left
&& 0 < elementBounds.right;
}
var noscriptImageLazyLoader = function(options) {
var container = document.createElement('div'),
defaultOptions = {
attribute: 'lazy-img',
events: ['resize', 'scroll', 'touchend'],
interval: 500,
placeholder: 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'
},
imageElementsInDOM = [],
interval,
processedLazyLoads = 0,
settingTextToNoscriptFailsInIE8AndBelow = document.createElement('noscript');
try {
settingTextToNoscriptFailsInIE8AndBelow.innerText = '';
} catch(err) {
return;
}
settingTextToNoscriptFailsInIE8AndBelow = void 0;
options = options || defaultOptions;
if(typeof options.attribute !== 'string') options.attribute = defaultOptions.attribute;
if(!Array.isArray(options.events)) options.events = defaultOptions.events;
if(typeof options.placeholder !== 'string') options.placeholder = defaultOptions.placeholder;
options.interval = options.interval == null ? defaultOptions.interval : ~~options.interval;
function attemptToLoadImage(temporaryImageElement, lazyLoadedImageSrc, imageElementInDOM) {
temporaryImageElement.onload = function() {
imageElementInDOM.src = temporaryImageElement.src;
processedLazyLoads++;
if(isFunction(options.lazyLoadCallback))
options.lazyLoadCallback(imageElementInDOM, lazyLoadedImageSrc, true);
};
temporaryImageElement.onerror = function() {
processedLazyLoads++;
if(isFunction(options.lazyLoadCallback))
options.lazyLoadCallback(imageElementInDOM, lazyLoadedImageSrc, false);
};
imageElementInDOM.removeAttribute('data-src');
temporaryImageElement.src = lazyLoadedImageSrc;
}
var loadImagesVisibleInViewport = throttle(function() {
if(processedLazyLoads < imageElementsInDOM.length) {
imageElementsInDOM.forEach(function(imageElementInDOM) {
var src = imageElementInDOM.getAttribute('data-src');
if(src && isElementInViewport(imageElementInDOM)) {
attemptToLoadImage(new Image(), src, imageElementInDOM);
}
});
} else {
clearInterval(interval);
options.events.forEach(function(event) {
window.removeEventListener(event, loadImagesVisibleInViewport, false);
});
imageElementsInDOM.length = 0;
}
}, 50);
Array.prototype.forEach.call(document.querySelectorAll('noscript[data-' + options.attribute + ']'), function(noscript) {
container.innerHTML = noscript.textContent || noscript.innerText;
var imageElementToLazyLoad = container.querySelector('img');
if(imageElementToLazyLoad) {
imageElementToLazyLoad.setAttribute('data-src', imageElementToLazyLoad.src);
imageElementToLazyLoad.src = options.placeholder;
noscript.parentNode.replaceChild(imageElementToLazyLoad, noscript);
imageElementsInDOM.push(imageElementToLazyLoad);
}
});
if(imageElementsInDOM.length) {
loadImagesVisibleInViewport();
options.events.forEach(function(event) {
window.addEventListener(event, loadImagesVisibleInViewport, false);
});
if(options.interval > 0)
interval = setInterval(loadImagesVisibleInViewport, options.interval);
}
container = void 0;
};
// some sample usage
!function() {
var debug = document.getElementById('debug');
debug.textContent = 'Initial viewport size: ' + window.innerWidth + 'x' + window.innerHeight;
setTimeout(function() {
debug.textContent += "\n" + 'Viewport size 1s later: ' + window.innerWidth + 'x' + window.innerHeight;
}, 1000);
noscriptImageLazyLoader({
lazyLoadCallback: function(imageElement, imageSrc, loaded) {
var elementBounds = imageElement.getBoundingClientRect();
debug.textContent += "\n" + imageElement.alt + ' [' + (loaded ? 'success' : 'fail') + '] @ ' + ~~elementBounds.left + 'x' + ~~elementBounds.top + ' / ' + ~~elementBounds.right + 'x' + ~~elementBounds.bottom;
}
});
}();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment