HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

Lazy loading social buttons on mouse enter

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
socialenterbuttonslazyloadingmouse

Problem

I am using the following code to lazy load some social buttons in my personal blog. Before continue, I would like to enumerate some dependencies first:

  • jQuery 2.1.4;



  • Using Font Awesome 4.1.0 (but should work with any icon/font);



  • Tested on the most recent Firefox, Chrome, Iceweasel and Safari;



So, the following HTML is using Font Awesome to present the Twitter and Facebook icons. It should be possible to do social actions even when no JavaScript is available, by clicking at the Icons:


  
    
          
          
        
  

  
    
          
          
        
  
  


Here is a snippet (Facebook button will not load, maybe due security protocols, SecurityError: The operation is insecure., you can still check the live site).



`

-















var tweetHover = function(e) {
$(e).hover(
function() { // mouse enter
if ($(this).hasClass("share-enabled")) {
// do nothing
} else {
if (typeof(twttr) != 'undefined') { // will load just the entered #tw-root
twttr.widgets.load(this);
$(this).addClass("share-enabled");
} else { // will load all #tw-root, and it sucks
$.getScript('http://platform.twitter.com/widgets.js');
$(this).addClass("share-enabled");
}
}
},
function() { // mouse leave

}
);
};
$(document).ready(function() {
tweetHover("#tw-root");
});

var facebook_sdk = '//connect.facebook.net/en_US/sdk.js';
if (document.documentElement.lang = 'pt-BR') {
facebook_sdk = '//connect.facebook.net/pt_BR/sdk.js';
};

var facebookHover = function(e) {
$(e).hover(
function() { // mouse enter
if ($(this).hasClass("share-enabled")) {
// do nothing
} else {
if (typeof(FB) != 'undefined') { // will load just the entered #fb-root
FB.XFBML.parse(this);

Solution

Notes on the code style:

  • Avoid deep nesting



  • Split high level logic and low level logic. This let's you see what a function does at a glance, and then dig deeper only if you need to. Code written this way is easier to understand. It also allows you to name the chunks of code with function names, rather than relying on comments.



  • This splitting can be done fractally, at all levels. Think of a book organized into sections, sub-sections, and perhaps sub-sub-sections.



  • Use function fnName() {} rather than var fnName = function() {} unless you have a good reason not to. It's shorter, and allows you to take advantage of js's nice "hoisting" feature, whereby you can define a function after you use it. This lets you put implementation details below high level logic.



As for the general approach, I'm not sure you need to do lazy loading. If you think the social buttons are important for you site, consider loading them as soon as the page loads. I know you are trying to respect your user's bandwidth, but I think the UX is worse with the lazy loading, because of the stutter and the button transformations.

It's been a while since I did FB integration, but I don't remember having to load such a large SDK. You might see if there's a lighter weight alternative. But I could be wrong on this point.

Below is a rewrite (untested) based on the principles above.

function loadFacebookWhenHovering(e) {

  var self = $(this);

  // The highest level of work.
  // Everything this function does is here to see in a single line
  // It adds a hover handler to the given element
  // Want to know the details of the handler?  Keep reading down...
  $(e).hover(mouseEnterCallback, function(){});

  function mouseEnterCallback() { // mouse enter

    // use a guard clause instead of an empty if clause
    if (self.hasClass("share-enabled"))
      return;

    // These 2 lines contain all the "high level" logic
    // of the mouse enter callback
    var isFBLoaded = (typeof (FB) != 'undefined');
    isFBLoaded ? enableWhenFBIsLoaded() : loadFBAndEnable();
  }

  // These helper functions implement the high level logic for the callback
  function loadFBAndEnable() {
    $.getScript(facebook_sdk, function(){
      FB.init({
        appId   : 'facebook-id-goes-here',
        xfbml   : true,
        version : 'v2.4'
      });
    });
    self.addClass("share-enabled");
    $(document).find("[id=fb-fa]").each(function(){self.remove()});
  }

  function enableWhenFBIsLoaded() {
    FB.XFBML.parse(self[0]); 
    self.addClass("share-enabled");
    self.find("#fb-fa").remove();
  }

};

Code Snippets

function loadFacebookWhenHovering(e) {

  var self = $(this);

  // The highest level of work.
  // Everything this function does is here to see in a single line
  // It adds a hover handler to the given element
  // Want to know the details of the handler?  Keep reading down...
  $(e).hover(mouseEnterCallback, function(){});

  function mouseEnterCallback() { // mouse enter

    // use a guard clause instead of an empty if clause
    if (self.hasClass("share-enabled"))
      return;

    // These 2 lines contain all the "high level" logic
    // of the mouse enter callback
    var isFBLoaded = (typeof (FB) != 'undefined');
    isFBLoaded ? enableWhenFBIsLoaded() : loadFBAndEnable();
  }

  // These helper functions implement the high level logic for the callback
  function loadFBAndEnable() {
    $.getScript(facebook_sdk, function(){
      FB.init({
        appId   : 'facebook-id-goes-here',
        xfbml   : true,
        version : 'v2.4'
      });
    });
    self.addClass("share-enabled");
    $(document).find("[id=fb-fa]").each(function(){self.remove()});
  }

  function enableWhenFBIsLoaded() {
    FB.XFBML.parse(self[0]); 
    self.addClass("share-enabled");
    self.find("#fb-fa").remove();
  }

};

Context

StackExchange Code Review Q#105329, answer score: 2

Revisions (0)

No revisions yet.