Created
February 10, 2020 18:27
-
-
Save EmielZuurbier/4e6d9ad4b0bf983bdc9877f44834fff9 to your computer and use it in GitHub Desktop.
Lazy loading function to load img, picture, audio or video, and background images.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Checks if an image has a data-src or data-srcset attribute | |
* and returns the answer in a Promise. | |
* | |
* @param {HTMLImageElement} image The image to check | |
* @returns {boolean} True when data attributes are present, false when not. | |
*/ | |
export const isImageLazyLoadable = image => | |
image.getAttribute('data-src') !== null || image.getAttribute('data-srcset' !== null); | |
/** | |
* Checks if the source tags of a media element has a data-src tags | |
* and returns the answer in a Promise. | |
* | |
* @param {(HTMLPictureElement|HTMLMediaElement)} media Picture, Video or Audio element. | |
* @returns {boolean} True when data attributes are present, false when not. | |
*/ | |
export const isMediaLazyLoadable = media => | |
Array.from(media.querySelectorAll('source')).some(source => | |
source.getAttribute('data-src') !== null); | |
/** | |
* Change the data-src attributes of the sources into src attributes. | |
* Returns an array with all the sources. | |
* | |
* @param {HTMLSourceElement[]} sources List of <source> elements. | |
* @returns {HTMLSourceElement[]} | |
*/ | |
export const lazyLoadSources = sources => | |
Array.from(sources).forEach(source => { | |
const src = source.getAttribute('data-src'); | |
if (src !== null) { | |
source.src = src; | |
source.removeAttribute('data-src'); | |
} | |
}); | |
/** | |
* Lazy load an image by adding a src attribute with the value from the data-src attribute. | |
* Also checks if the element has a srcset that needs to be lazyloaded. | |
* Returns a Promise with the image element on resolve. | |
* | |
* @param {HTMLImageElement} image Image element to lazyload. | |
* @returns {Promise<HTMLImageElement>} Promise with the image element on resolve. | |
*/ | |
export const lazyLoadImage = image => | |
new Promise(resolve => { | |
const pseudo = new Image(); | |
const sizes = image.getAttribute('sizes'); | |
const srcset = image.getAttribute('data-srcset'); | |
const src = image.getAttribute('data-src'); | |
const imageOnLoad = () => { | |
image.srcset = srcset ? srcset : ''; | |
image.src = src; | |
image.removeAttribute('data-src'); | |
resolve(image); | |
}; | |
pseudo.addEventListener('load', imageOnLoad, {once: true}); | |
pseudo.sizes = sizes !== null ? sizes : ''; | |
pseudo.srcset = srcset !== null ? srcset : ''; | |
pseudo.src = src !== null ? src : ''; | |
}); | |
/** | |
* Lazy load a background-image by setting the property as a inline CSS. | |
* Returns a Promise with the element on resolve. | |
* | |
* @param {HTMLElement} image Image element to lazyload. | |
* @returns {Promise<HTMLElement>} Promise with the image element on resolve. | |
*/ | |
export const lazyLoadBackgroundImage = element => | |
new Promise(resolve => { | |
const pseudo = new Image(); | |
const src = element.getAttribute('data-src'); | |
const imageOnLoad = () => { | |
element.style.backgroundImage = `url(${src})`; | |
element.removeAttribute('data-src'); | |
resolve(element); | |
}; | |
pseudo.addEventListener('load', imageOnLoad, {once: true}); | |
pseudo.src = src !== null ? src : ''; | |
}); | |
/** | |
* Lazy load a picture element by changing the data-src of the sources and image inside | |
* the picture element. The function returns a Promise with the picture element on resolve. | |
* | |
* @uses lazyLoadSources | |
* @uses lazyLoadImage | |
* @param {HTMLPictureElement} picture Picture element to lazyload. | |
* @returns {Promise<HTMLPictureElement>} Promise with the picture element on resolve. | |
*/ | |
export const lazyLoadPicture = picture => | |
new Promise(async resolve => { | |
const sources = picture.querySelectorAll('source'); | |
const image = picture.querySelector('img'); | |
lazyLoadSources(sources); | |
if (image !== null && isImageLazyLoadable(image)) | |
await lazyLoadImage(image); | |
resolve(picture); | |
}); | |
/** | |
* Lazy load a media element like Video or Audio by adding a adding a src attribute with the value | |
* from the data-src attribute that is found on the <source> tags inside the media element. | |
* The media is then loaded. When the media can be played through to the end without too | |
* much buffering it will resolve a promise with the media element as its value. | |
* | |
* @uses lazyLoadSources | |
* @param {HTMLMediaElement} media Video or Audio element to lazy load. | |
* @returns {Promise<HTMLMediaElement>} Promise with the video element on resolve. | |
*/ | |
export const lazyLoadMedia = media => | |
new Promise(resolve => { | |
const videoOnCanPlayThrough = () => resolve(media); | |
const sources = media.querySelectorAll('source'); | |
lazyLoadSources(sources); | |
media.addEventListener('canplaythrough', videoOnCanPlayThrough, {once: true}); | |
media.load(); | |
}); | |
/** | |
* Lazy loads images that contain a data-src attribute. | |
* Returns a Promise that resolves with the image elements when all loads have resolved. | |
* | |
* @function lazyLoadAllImages | |
* @uses lazyLoadImage | |
* @param {HTMLImageElement[]} [images=document.images] Array of image elements to load. | |
* @returns {Promise<HTMLImageElement[]>} | |
*/ | |
export const lazyLoadAllImages = (images = document.images) => | |
Promise.all([...images].map(lazyLoadImage)); | |
/** | |
* Lazy loads media element that have sources that contain a data-src attribute and. | |
* Returns a Promise that resolves with the media elements when all loads have resolved. | |
* | |
* @function lazyLoadAllMedia | |
* @uses lazyLoadMedia | |
* @param {HTMLImageElement[]} media Array of media elements to load. | |
* @returns {Promise<HTMLImageElement[]>} | |
*/ | |
export const lazyLoadAllMedia = media => | |
Promise.all([...media].map(lazyLoadMedia)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment