Create a gist now

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Optimised async loading of cross-domain scripts
/*
* Updated to use the function-based method described in http://www.phpied.com/social-button-bffs/
* Better handling of scripts without supplied ids.
*
* N.B. Be sure to include Google Analytics's _gaq and Facebook's fbAsyncInit prior to this function.
*/
(function(doc, script) {
var js,
fjs = doc.getElementsByTagName(script)[0],
add = function(url, id) {
if (doc.getElementById(id)) {return;}
js = doc.createElement(script);
js.src = url;
id && (js.id = id);
fjs.parentNode.insertBefore(js, fjs);
};
// Google Analytics
add(('https:' == location.protocol ? '//ssl' : '//www') + '.google-analytics.com/ga.js', 'ga');
// Google+ button
add('https://apis.google.com/js/plusone.js');
// Facebook SDK
add('//connect.facebook.net/en_US/all.js', 'facebook-jssdk');
// Twitter SDK
add('//platform.twitter.com/widgets.js', 'twitter-wjs');
}(document, 'script'));
@mathiasbynens

This comment has been minimized.

Show comment
Hide comment
@mathiasbynens

mathiasbynens Jun 15, 2011

Nice!

Some quick feedback:

  • Why .cloneNode(true) though? It seems .cloneNode(false) would be good enough in this case.
  • Also, you could make it z.async = z.src = u[i]; if you wanted to (although that’s probably less readable). If optimal Firefox 3.6 support is not a concern you could skip setting .async entirely.
  • You could get rid of a variable by re-using z outside the while loop instead of t.
(function(d,e){

    var u = [
        ('https:'==location.protocol?'//ssl':'//www')+'.google-analytics.com/ga.js', // Google Analytics
        'https://apis.google.com/js/plusone.js', // Google +1 Button
        '//connect.facebook.net/en_US/all.js' // Facebook JS SDK
    ],
    i = u.length,
    f = d.createDocumentFragment(),
    s = d.createElement(e),
    z;

    while (i--) {
        z = s.cloneNode(false);
        z.async = z.src = u[i];
        f.appendChild(z);
    }

    (z = d.getElementsByTagName(e)[0]).parentNode.insertBefore(f, z);

}(document,'script'));

Nice!

Some quick feedback:

  • Why .cloneNode(true) though? It seems .cloneNode(false) would be good enough in this case.
  • Also, you could make it z.async = z.src = u[i]; if you wanted to (although that’s probably less readable). If optimal Firefox 3.6 support is not a concern you could skip setting .async entirely.
  • You could get rid of a variable by re-using z outside the while loop instead of t.
(function(d,e){

    var u = [
        ('https:'==location.protocol?'//ssl':'//www')+'.google-analytics.com/ga.js', // Google Analytics
        'https://apis.google.com/js/plusone.js', // Google +1 Button
        '//connect.facebook.net/en_US/all.js' // Facebook JS SDK
    ],
    i = u.length,
    f = d.createDocumentFragment(),
    s = d.createElement(e),
    z;

    while (i--) {
        z = s.cloneNode(false);
        z.async = z.src = u[i];
        f.appendChild(z);
    }

    (z = d.getElementsByTagName(e)[0]).parentNode.insertBefore(f, z);

}(document,'script'));
@necolas

This comment has been minimized.

Show comment
Hide comment
@necolas

necolas Jun 15, 2011

Thanks! I've updated the Gist to include your changes

Owner

necolas commented Jun 15, 2011

Thanks! I've updated the Gist to include your changes

@rafaehlers

This comment has been minimized.

Show comment
Hide comment
@rafaehlers

rafaehlers Nov 26, 2011

So, this means that can we replace the script that's in html5boilerplate for this one now?

window._gaq = [['_setAccount','UA-00000'],['_trackPageview']];
Modernizr.load({
    load: ('https:' == location.protocol ? '//ssl' : '//www') + '.google-analytics.com/ga.js'
});

So, this means that can we replace the script that's in html5boilerplate for this one now?

window._gaq = [['_setAccount','UA-00000'],['_trackPageview']];
Modernizr.load({
    load: ('https:' == location.protocol ? '//ssl' : '//www') + '.google-analytics.com/ga.js'
});
@paulirish

This comment has been minimized.

Show comment
Hide comment
@paulirish

paulirish Dec 1, 2011

eddie adapted this to only load social scripts on non-mobile http://jsfiddle.net/eddiemachado/MH5qe/2/

eddie adapted this to only load social scripts on non-mobile http://jsfiddle.net/eddiemachado/MH5qe/2/

@necolas

This comment has been minimized.

Show comment
Hide comment
@necolas

necolas Dec 1, 2011

Neat. Should probably be modified to be on a per-script basis so that you can still load GA or other desired scripts with the function.

I'm sure that wrapper could be handy for most cases, but just to note that the FB and Twitter SDKs are sometimes also used for things like authentication/follow which may still be desired in a mobile context.

Owner

necolas commented Dec 1, 2011

Neat. Should probably be modified to be on a per-script basis so that you can still load GA or other desired scripts with the function.

I'm sure that wrapper could be handy for most cases, but just to note that the FB and Twitter SDKs are sometimes also used for things like authentication/follow which may still be desired in a mobile context.

@necolas

This comment has been minimized.

Show comment
Hide comment
@necolas

necolas Dec 1, 2011

@eddiemachado Oh also, if you wanted to provide non-script fallback links for users (like just link to your FB and G+ pages rather than have Like / +1 buttons), then you can just include them within the div's that get turned into buttons by the FB and Google scripts. Like you said, those could be styled too!

Owner

necolas commented Dec 1, 2011

@eddiemachado Oh also, if you wanted to provide non-script fallback links for users (like just link to your FB and G+ pages rather than have Like / +1 buttons), then you can just include them within the div's that get turned into buttons by the FB and Google scripts. Like you said, those could be styled too!

@necolas

This comment has been minimized.

Show comment
Hide comment
@necolas

necolas Dec 1, 2011

sigh ...Facebook

Owner

necolas commented Dec 1, 2011

sigh ...Facebook

@necolas

This comment has been minimized.

Show comment
Hide comment
@necolas

necolas Dec 1, 2011

Sneaky! I like it.

Owner

necolas commented Dec 1, 2011

Sneaky! I like it.

@fundon

This comment has been minimized.

Show comment
Hide comment
@fundon

fundon Dec 15, 2011

@necolas
I want use 'createDocumentFragment' and load css, but ie fail.
This is my testcase.
https://gist.github.com/1480368

fundon commented Dec 15, 2011

@necolas
I want use 'createDocumentFragment' and load css, but ie fail.
This is my testcase.
https://gist.github.com/1480368

@necolas

This comment has been minimized.

Show comment
Hide comment
@necolas

necolas Feb 20, 2012

Removed the doc frag from the latest update because previous perf tests failed to produce any significant difference. Also, dropping the doc frag made it simpler to include callback functions (which I needed on a couple of occasions).

Owner

necolas commented Feb 20, 2012

Removed the doc frag from the latest update because previous perf tests failed to produce any significant difference. Also, dropping the doc frag made it simpler to include callback functions (which I needed on a couple of occasions).

@necolas

This comment has been minimized.

Show comment
Hide comment
@necolas

necolas Feb 23, 2012

@eddiemachado I've also realised (unless I missed something) that your proposed "non-mobile only" wrapper prevents the sharing buttons being loaded in any browser that doesn't support CSS3 Media Queries.

Owner

necolas commented Feb 23, 2012

@eddiemachado I've also realised (unless I missed something) that your proposed "non-mobile only" wrapper prevents the sharing buttons being loaded in any browser that doesn't support CSS3 Media Queries.

@MoOx

This comment has been minimized.

Show comment
Hide comment
@MoOx

MoOx Mar 8, 2012

If you add #xfbml=1&appId=null at the end of the facebook url, you does need fbAsyncInit. And it work quite well.

// Facebook SDK
add('//connect.facebook.net/en_US/all.js#xfbml=1&appId=null', 'facebook-jssdk');

Btw, maybe it's risky, but to make adaptive language, I'm using navigator.language

add('//connect.facebook.net/' + navigator.language.replace('-', '_') + '/all.js#xfbml=1&appId=null', 'facebook-jssdk');

MoOx commented Mar 8, 2012

If you add #xfbml=1&appId=null at the end of the facebook url, you does need fbAsyncInit. And it work quite well.

// Facebook SDK
add('//connect.facebook.net/en_US/all.js#xfbml=1&appId=null', 'facebook-jssdk');

Btw, maybe it's risky, but to make adaptive language, I'm using navigator.language

add('//connect.facebook.net/' + navigator.language.replace('-', '_') + '/all.js#xfbml=1&appId=null', 'facebook-jssdk');
@zenopopovici

This comment has been minimized.

Show comment
Hide comment
@zenopopovici

zenopopovici Feb 4, 2013

You could also add the LinkedIn SDK.

 // LinkedIn SDK 
 add('//platform.linkedin.com/in.js');

You could also add the LinkedIn SDK.

 // LinkedIn SDK 
 add('//platform.linkedin.com/in.js');
@ngryman

This comment has been minimized.

Show comment
Hide comment
@ngryman

ngryman Mar 28, 2013

Here is an updated version including the updates of @mathiasbynens from his post on the similar topic + some adjustments.

JSFiddle: http://jsfiddle.net/ngryman/cEuxD/
Fork: https://gist.github.com/ngryman/5266324

  • using all relative urls: google plus seems to work wo/ https, and gga now works w/ relative urls.
  • not using document fragment as I find it a little bit overkill :)
  • using the iframe version of the Facebook button (not in the docs anymore I think, but works).
(function(d, u) {
    var s = d.scripts[0],
        i = u.length, g;
    while (i--) {
        g = d.createElement('script');
        g.src = '//' + u[i] + '.js';
        s.parentNode.insertBefore(g, s);
    }
}(document, [
    // Google Analytics
    'google-analytics.com/ga',
    // Google+ button
    'apis.google.com/js/plusone',
    // Facebook SDK
    'connect.facebook.net/en_US/all',
    // Twitter SDK
    'platform.twitter.com/widgets'
]));

ngryman commented Mar 28, 2013

Here is an updated version including the updates of @mathiasbynens from his post on the similar topic + some adjustments.

JSFiddle: http://jsfiddle.net/ngryman/cEuxD/
Fork: https://gist.github.com/ngryman/5266324

  • using all relative urls: google plus seems to work wo/ https, and gga now works w/ relative urls.
  • not using document fragment as I find it a little bit overkill :)
  • using the iframe version of the Facebook button (not in the docs anymore I think, but works).
(function(d, u) {
    var s = d.scripts[0],
        i = u.length, g;
    while (i--) {
        g = d.createElement('script');
        g.src = '//' + u[i] + '.js';
        s.parentNode.insertBefore(g, s);
    }
}(document, [
    // Google Analytics
    'google-analytics.com/ga',
    // Google+ button
    'apis.google.com/js/plusone',
    // Facebook SDK
    'connect.facebook.net/en_US/all',
    // Twitter SDK
    'platform.twitter.com/widgets'
]));
@tomasdanilevicius

This comment has been minimized.

Show comment
Hide comment
@tomasdanilevicius

tomasdanilevicius Apr 30, 2013

@zenopopovici - to set api_key, LinkedIn needs a callback. I forked this GIST a while ago and added callback method, you can preview it here: @3952471 . I know it's outdated, but I hope you'll be able to figure it out.

@zenopopovici - to set api_key, LinkedIn needs a callback. I forked this GIST a while ago and added callback method, you can preview it here: @3952471 . I know it's outdated, but I hope you'll be able to figure it out.

@anselm-urban

This comment has been minimized.

Show comment
Hide comment
@anselm-urban

anselm-urban May 4, 2013

How can I add jQuery?

How can I add jQuery?

@maartentibau

This comment has been minimized.

Show comment
Hide comment
@maartentibau

maartentibau Jul 3, 2013

I would change the while statement to this

while (i--) {
    var  src = (u[i].lastIndexOf('http', u[i]) === -1) ? '//' + u[i] : u[i];

    g = d.createElement('script');
    g.src += (u[i].indexOf('.js', u[i].length - 3) === -1) ? src + '.js' : src;
    s.parentNode.insertBefore(g, s);
}

This makes the following things possible:

  • it's possible to add scripts with ".js" at the end
  • it's possible to add files with an absolute URL

I would change the while statement to this

while (i--) {
    var  src = (u[i].lastIndexOf('http', u[i]) === -1) ? '//' + u[i] : u[i];

    g = d.createElement('script');
    g.src += (u[i].indexOf('.js', u[i].length - 3) === -1) ? src + '.js' : src;
    s.parentNode.insertBefore(g, s);
}

This makes the following things possible:

  • it's possible to add scripts with ".js" at the end
  • it's possible to add files with an absolute URL
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment