Lazy loading for Javascript

Posted on September 25, 2011
by

In a previous post, I was discussing how to lazy load a Facebook widget, so that it loads only when really needed. I have put my thoughts further, and come up with a general way to lazy load any kind of JavaScript snippet.

I always take for example the Facebook widgets, which are always very heavy and load many files (include JS, CSS and images).If that widget is not in the viewport when your visitor loads your page at the beginning, and if it’s visible only after he scrolls, then you can tweak the performances of your page by lazy loading that widget. Note that it works for any kind of JavaScript snippet that would have a visible effect only after the user scrolls your page down.

In this post, I’ll introduce my jQuery plugin and show you a demo of how it works, but I’m not going to go very deep into the interior mechanisms (for that, see the Google Code page).

jQuery lazy loading JS

Example: how to lazy load the Facebook Like Box

Let’s say you have a Facebook Like Box in your page, and it’s located far in the page, so far that the user needs to scroll before seeing it on his screen. The code given by Facebook is that one:

<div id="fb-root"></div>
 
<script>(function(d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) {return;}
js = d.createElement(s); js.id = id;
js.src = "//connect.facebook.net/en_US/all.js#xfbml=1";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));</script>
 
<div class="fb-like-box" data-href="http://www.facebook.com/platform" data-width="292" data-show-faces="true" data-stream="false" data-header="false"></div>

This script will of course load the widget right away when the page initially loads. Let’s say the placeholder (the fb-like-box div) is located far and you want to lazy load it only once the user scrolled down enough to have it in viewport. The only thing you need to change is this:

$('.fb-like-box').lazyloadjs(function(d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) {return;}
js = d.createElement(s); js.id = id;
js.src = "//connect.facebook.net/en_US/all.js#xfbml=1";
fjs.parentNode.insertBefore(js, fjs);
})(document, 'script', 'facebook-jssdk');

Basically, you just have to surround the JavaScript code by this
$('.fb-like-box').lazyloadjs( ... );

The selector (.fb-like-box) must be the placeholder of your widget, which is a div in our case. This placeholder will be watched until it gets into the viewport. The lazyloadjs() function accepts only one argument, which must be a pointer to a function (either a named function or an anonymous function would do). Once the placeholder gets into the viewport, the function you give in parameter will be executed.

Actually, in this special case of the Facebook Like Box, we need to adapt the given snippet to the following:

$('.fb-like-box').lazyloadjs(function() {
var d = document;
var s = 'script';
var id = 'facebook-jssdk';
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) {return;}
js = d.createElement(s); js.id = id;
js.src = "//connect.facebook.net/en_US/all.js#xfbml=1";
fjs.parentNode.insertBefore(js, fjs);
});

Why? Because the previous construction function(){}(); was calling the function right away after its definition and returning its result, instead of returning a pointer to that function. And we don’t want that function to be executed right away, we absolutely want it to be executed only when needed, later.

Second point, my plugin doesn’t allow you to use parameters in your function, so you need to make special adjustments for that too.

And voilà. Most of the time you will probably not need to modify your JavaScript snippet to lazy load it, but bare in mind that you MUST give a reference to a function to lazyloadjs().

Live example

The Facebook widget below only loaded when you scrolled down enough to see it in your viewport 😉 Don’t believe me? Go back up, refresh the page and start to scroll down again…

Download

You can download the latest source or the minified version.

If you see bugs or want to help me improving it, you can leave a comment or join the Google Code project page: jquery-lazyloadjs

About the author

Cyril Mazur is a serial web entrepreneur with experience in various fields: online dating, forex & finance, blogging, online advertising... who enjoys building things that people like to use.

13 comments

  1. Gercek
    on November 21, 2011
    Is there a way to make it work with Twitter embed code?
    <code>


    new TWTR.Widget({
    version: 2,
    type: 'profile',
    rpp: 6,
    interval: 5000,
    width: 210,
    height: 207,
    theme: {
    shell: {
    background: '#adcff4',
    color: '#0862a2'
    },
    tweets: {
    background: '#cde5ff',
    color: '#444444',
    links: '#0862a2'
    }
    },
    features: {
    scrollbar: false,
    loop: false,
    live: true,
    hashtags: true,
    timestamp: true,
    avatars: false,
    behavior: 'default'
    }
    }).render().setUser('google').start();

    </code>
  2. Cyril
    on November 21, 2011
    Yes Gercek, it can work with the Twitter widget, just that way:

    <code>
    $('.twitter-box').lazyloadjs(function() {
    new TWTR.Widget({
    version: 2,
    type: 'profile',
    rpp: 6,
    interval: 5000,
    width: 210,
    height: 207,
    theme: {
    shell: {
    background: '#adcff4',
    color: '#0862a2'
    },
    tweets: {
    background: '#cde5ff',
    color: '#444444',
    links: '#0862a2'
    }
    },
    features: {
    scrollbar: false,
    loop: false,
    live: true,
    hashtags: true,
    timestamp: true,
    avatars: false,
    behavior: 'default'
    }
    }).render().setUser('google').start();
    });
    </code>

    Provided that you have an HTML element with the CSS class "twitter-box" somewhere in your page.
  3. Sergio
    on January 10, 2012
    I tried your code but it displays the following error :

    $(".fb-like-box").lazyloadjs is not a function

    Do you have any suggestions?
  4. Cyril
    on January 10, 2012
    Hi Sergio,

    Is "$" the name for your jQuery object or is it another one? Do you use another JS library at the same time like PrototypeJS? In that case, the name of your jQuery object is usually "jQuery" instead of "$".

    Other possibility, do you include the lazyloadjs.js file before or after trying to call "$(“.fb-like-box”).lazyloadjs"?
  5. Sergio
    on January 10, 2012
    Thanks Cyril,

    The problem was in the file path lazyloadjs.js

    I was using relative path, switched to the absolute path, everything worked perfectly.
  6. Cyril
    on January 10, 2012
    Am glad to hear it :-) Keep up the good work
  7. sudhir
    on January 1, 2013
    hey very great script but i could not figure out how it work on blogger(blogspot) i tried this script in post but unfortunately i am not successful can u tell me what i did worng ?



    (function(d, s, id) {
    var js, fjs = d.getElementsByTagName(s)[0];
    if (d.getElementById(id)) {return;}
    js = d.createElement(s); js.id = id;
    js.src = "//connect.facebook.net/en_US/all.js#xfbml=1";
    fjs.parentNode.insertBefore(js, fjs);
    }(document, 'script', 'facebook-jssdk'));








    jQuery('.fb-like-box').lazyloadjs(function() {
    var d = document;
    var s = 'script';
    var id = 'facebook-jssdk';
    var js, fjs = d.getElementsByTagName(s)[0];
    if (d.getElementById(id)) {return;}
    js = d.createElement(s); js.id = id;
    js.src = "//connect.facebook.net/en_US/all.js#xfbml=1";
    fjs.parentNode.insertBefore(js, fjs);
    });
  8. Cyril
    on January 1, 2013
    You code looks good sudhir, could you tell me if you see any error in the JS console? maybe my guess is that jQuery is not included in blogspot? I never used blogspot personally.
  9. sudhir
    on January 4, 2013
    hey thanks for your reply i add three scripts before body tag









    $(&#039;.fb-like-box&#039;).lazyloadjs(function() {
    var d = document;
    var s = &#039;script&#039;;
    var id = &#039;facebook-jssdk&#039;;
    var js, fjs = d.getElementsByTagName(s)[0];
    if (d.getElementById(id)) {return;}
    js = d.createElement(s); js.id = id;
    js.src = &quot;//connect.facebook.net/en_US/all.js#xfbml=1&quot;;
    fjs.parentNode.insertBefore(js, fjs);
    });



    and in my post i add








    so facebook like box is appearing in my post but it is not deferring till scrolling when i check console it give me error


    Uncaught TypeError: Object [object Object] has no method 'lazyloadjs'


    can you tell me what should i do to make it work.You can see my blog where i implement your code.

    http://sudhirdudeja.blogspot.in/2013/01/test-post.html


    i will wait for your reply thanks :)
  10. sudhir
    on January 4, 2013
    lol i sorted it out i included jquery twice in template so it was giving me error but thanks for your great script i was searching this kind of script on web from many months and tried lot of scripts but non was so good as your
  11. Cyril
    on January 12, 2013
    ah good thing you sorted it out :)
  12. Michael
    on February 11, 2013
    Hi,

    Thank you for this code!

    Can I make this work inside a widget? I have the facebook code loaded in an iframe. If I try to load html5 code provided by facebook it won't load on my screen. And if I can load it in a widget somehow, how do I call your function and where an my server do I copy your script to?

    As you might have understood, I'm a noob when it comes to coding etc. However, I would very much like to make this work, because the long loading of the social widgets is realy irritating.
  13. Cyril
    on February 19, 2013
    Hi Michael, I don't think that would work with the iframe Facebook widget, since my piece of code executes Javascript.

    However you could try something like

    $('.my-div').append('<iframe .........>');

    (and replace with the correct class name and correct iframe snippet)

Leave a Reply