I’m currently working on a project for Intel’s HTML5 Hub in which I require some image lazy-loading for an HTML5 showcase piece that’s high in image content. After a quick Google search for an existing lazy-load solution there was yet another mass of outdated scripts or jQuery plugins that were too time consuming to search through or modify for the project - so I ended up writing my own.
Echo.js is probably as simple as image lazy loading gets, it’s less than 1KB minified and is library agnostic (no jQuery/Zepto/other).
Lazy-loading works by only loading the assets needed when the elements ‘would’ be in view, which it’ll get from the server for you upon request, which is automated by simply changing the image src attribute. This is also an asynchronous process which also benefits us.
Using Echo is really easy, just include an original image to be used as a placeholder, for the demo I am using a simple AJAX .gif spinner as a background image with a transparent .gif placeholder so the user will always see something is happening, but you can use whatever you like.
Here’s the markup to specify the image source, which is literal so you’ll be able to specify the full file path (even the full http:// if you like) which makes it easier when working with directories.
Just drop the script into your page before the closing </body> tag and let it do its thing. For modern browsers I’ve used the DOMContentLoaded event incase you really need it in the <head>, which is a native ‘DOM Ready’, and a fallback to onload for IE7/8 if you need to go that far so all works nicely.
As always, I’ll talk through the script for those interested in the behind the scenes working. Here’s the full script:
The script takes an Object-Orientated approach, instantiating the Echo object (which is our Function constructor) on each element instance of NodeList inside our for loop. You can see this instantiation at the end of the script, using the new operator.
The first main chunk of code we see if an anonymous function expression which acts as our Constructor. Following convention, Constructor function names should have the first letter capitalised:
I pass in the elem argument, which will be the current element inside the for loop in which the plugin is called upon, and call render.(); and listen(); internally, this will run the prototype functions that the Object inherits.
Next is an empty array:
This empty array will act as our data store for pushing our images that need lazy-loading into. It’s a good practice to use arrays for this type of thing so we can remove images that are already loaded from the same array, this will prevent our loops iterating over the same array, it may as well perform faster and loop over fewer items.
Next, here’s a neat little function to detect whether the element is in view:
Next up is a very simple function that switches the current image’s src attribute to the associated data-echo attribute once it’s needed:
If a callback is present, it will run (I do pass in a callback here, but to prevent errors it’s good to simply if statement this stuff).
The next function I’ve setup to check if the current element exists in the array, and if it does, it removes it using the .splice() method on the current index to remove ‘itself’:
The OO piece of the script looks inside the prototype extension, which has a few functions inside. The first is the init() function, that simply pushes the current element into our data store array. The render() function checks to see if an addEventListener event exists, which will then invoke the echoImages function once the DOMContentLoaded event is fired. If it doesn’t exist, likely inside IE7/8, it’ll just run onload. The listen() function will just run the function again each time the window is scrolled, to poll and see if any elements come into view to work its magic some more.
The final piece of the script is the beautiful API where you invoke a new Object on each item in a NodeList: