Saturday 25 June 2011

Loading Social Media Code Asynchronously

Preventing Slow Page Loads By Loading Widgets Asynchronously

I have noticed on a number of sites that use such as the popular Add This widget that for some reason many people using this code have caused problems for themselves by adding the <SCRIPT> tag that loads the widget in every place that they want the widget to display.

On a news blog with 10 articles this means that the same <SCRIPT> could be referenced 10 times. Now I know browsers are clever enough to know what they have loaded and utilise caching but as every user of Google Adsense knows having to embed <SCRIPT> tags in the DOM at the place where you want the advert to display instead of just referencing it once at the bottom of the HTML or loading it in with Javascript can cause slow page loads as the browser will hang when it comes across a script until the content has been loaded.

I have personally spent ages trying to hack Google AdSenses code about to utilise the same asynchronous loading that they now use for their Analytics code but to no avail. There code loads in multiple iframes and any hacking seems to trigger a flag their end that probably signifies to them some kind of fraudulent abuse.

However for other kinds of widgets including the AddThis widget there is no need to reference the script multiple times and I am busy updating some of my sites to utilise another method which can be seen on the following test page >> http://www.strictly-software.com/AddThis_test.htm


Loading addthis.com social media widgets asynchronously

I wanted to keep the example as simple as possible so in that regards if you use IE it's best off to view it in IE 9 as the only cross browser code I have added is a very basic addEvent function and an override for document.getElementsByClassName which doesn't exist pre IE 9.

Other browsers should work without a problem i.e Chrome, FireFox, Safari, Opera and any other standard compliant browser that supports the DOM 2 Event Model.


Specifying where the Social Media widgets will appear

HTML 5 makes use of custom attributes that validate correctly as long as they are prefixed by the name data- therefore I have utilised this much needed feature to specify the URL and the Title of the item that is to be bookmarked on the desired Social Media site.

You might have a page with multiple items, blog articles or stories each with their own Social Media widget and instead of defaulting to the URL and Title of the current document it is best to specify the details of the article the Add This widget refers to.

The HTML code for outputting a widget is below:


<div class="addthis_wrapper" data-url="http://www.strictly-software.com/twitter-translator" data-title="Twitter Translator Tool" >


Notice how the URL and Title are referenced by the

data-url="http://www.strictly-software.com/twitter-translator" data-title="Twitter Translator Tool"

attributes. You can read more about using custom HTML5 attributes as they are becoming more and more commonly used.
Changing the placeholders into Social Media widgets

Once the placeholder HTML elements are inserted into your DOM where you want the addthis widget to appear instead of doing what many Wordpress plugins and coders do and adding a reference to the hosted script next to each DIV you just need to add the following code in the footer of your file.

You can either wrap the code in an on DOM load event or an on Window load or just as I have done wrap it in a self calling function which means it will run as soon as the Browser gets to it.

You can view the code is more detail on my test page but to keep things simple I have just done enough cross browser tweaks to make it run in most browsers including older IE. There might be some issues with the actual addthis code that is loaded in from their own site but I cannot do anything about their dodgy code!

The Javascript code to change the DIV's into Social Media Widgets

(function(){
// this wont be supported in older browsers such as IE 8 or less
var els=document.getElementsByClassName('addthis_wrapper');

if(els && els.length >0){

// create a script tag and insert it into the DOM in the HEAD
var at=document.createElement('script');at.type='text/javascript';

// make sure it loads asynchronously so it doesn't block the DOM loading
at.async=true;
at.src=('https:'==document.location.protocol?'https://':'http://')+'s7.addthis.com/js/250/addthis_widget.js?pub=xa-4a42081245d3f3f5';

// find the first <SCRIPT> element and add it before
var s=document.getElementsByTagName('script')[0];s.parentNode.insertBefore(at,s);

// loop through all elements with the class=addthis_container
for(var x=0;x<els.length;x++){

// store pointer
var el = els[x];

// get our custom attribute values for the URL to bookmark and the title that describes it defaulting to the placeholders that
// will take the values from the page otherwise. By using data-title and data-url we are HTML 5 compliant
var title = els[x].getAttribute("data-title") || "[TITLE]";
var url = els[x].getAttribute("data-url") || "[URL]";

// create an A tag
var a=document.createElement('A');
a.setAttribute('href','http://www.addthis.com/bookmark.php');

// create an IMG tag
var i=document.createElement('IMG');
i.setAttribute('src','http://s7.addthis.com/static/btn/lg-share-en.gif');

// set up your desired image sizes
i.setAttribute('width','125');
i.setAttribute('height','16');
i.setAttribute('alt','Bookmark and Share');
i.style.cssText = 'border:0px;';

// append the image to the A tag
a.appendChild(i);

// append the A tag (and image) to the DIV with the class=addthis_container
el.appendChild(a);

// using DOM 2 event model to add events to our element - remember if you want to support IE before version 9 you will need to either use a wrapper addEvent
// function that uses addEvent for IE (and Opera) and addEventListener for IE 9, Firefox, Opera, Webkit and any other proper broweser
addEvent(a,"mouseover",function(e){if(!addthis_open(this, '', url, title)){StopEvent(e,a)}});
addEvent(a,"mouseout",function(){addthis_close});
addEvent(a,"click",function(e){if(!addthis_sendto()){StopEvent(e,a)}});

// cleanup
el=a=i=title=url=null;
}
}
})();


The code is pretty simple and makes use of modern browsers support for document.getElementsByClassName to find all elements with the class we identified our social media containers with. This can obviously be replaced with a selector engine such as Sizzle if required.

First off the code builds a SCRIPT element and inserts it into the DOM in the HEAD section of the page. The important thing to note here is that as this code is at the bottom of the page nothing should block the page from loading and even if the SCRIPT block was high up in the DOM the code only runs once the DOM has loaded anyway.
// create a script tag and insert it into the DOM in the HEAD
var at=document.createElement('script');at.type='text/javascript';

// make sure it loads asysnchronously so it doesn't block the DOM loading
at.async=true;
at.src=('https:'==document.location.protocol?'https://':'http://')+'s7.addthis.com/js/250/addthis_widget.js?pub=xa-4a42081245d3f3f5';

// find the first <SCRIPT> element and add it before
var s=document.getElementsByTagName('script')[0];s.parentNode.insertBefore(at,s);




The code then loops through each node that matches creating an A (anchor) tag and an IMG (image) tag with the correct dimensions and attributes for the title and URL. If none are supplied then the system will default to the document.location.href and document.title if no values are supplied which might be fine if it's the only widget on the page but if not values should be specified.


Events are then added to the A (anchor) tag to fire the popup of the AddThis DIV and to close it again and I have used a basic addEvent wrapper function to do this along with a StopEvent function to prevent event propagation and these are just basic cross browser functions to handle old cruddy browsers that no-one in their right mind should be using any more. As this is just an example I am not too bothered if this code fails in IE 4 or Netscape as its just an example of changing what is often plugin generated code.


You can see an example of the code here >>

http://www.strictly-software.com/addthis_test.htm

This methodology is being used more and more by developers but there are still many plugins available for Wordpress and Joomla that insert remote loading SCRIPTs all throughout the DOM as well as using document.write to insert remote SCRIPTS. These methods should be avoided if at all possible especially if you find that your pages hang when loading and as you can see from the example code it is pretty simple to convert to your favourite framework if required.

2 comments:

Julia said...

Well thanks for sharing your knowledge or your insight of social media code. It make sense and I gain ideas from your article. Thanks. :D

Ollie said...

Great stuff. I'll try this one a site I'm working on.