JavaScript downloads block the loading of other page components. That’s why it’s important (make that critical) to load script files in a non-blocking asynchronous fashion. If this is new to you, you can start here or here.

In this post I’ll examine the topic from the perspective of a third party – when you’re the third party, providing a snippet for other developers to include on their pages. Be it an ad, a plugin, widget, visits counter, analytics, or anything else.

Let’s see in much detail how this issue is addressed in Facebook’s JavaScript SDK.

The Facebook plugins JS SDK

The Facebook JavaScript SDK is a multi-purpose piece of code that lets you integrate Facebook services, make API calls and load social plugins such as the Like button.

The task of the SDK when it comes to Like button and other social plugins is to parse the page’s HTML code looking for elements (such as <fb:like> or <div class="fb-like">) to replace with a plugin. The plugin itself is an iframe that points to something like with the appropriate URL parameters and appropriately sized.

This is an example of one such plugin URL:

The JavaScript SDK has a URL like so:

The question is how do you include this code on your page. Traditionally it has been the simplest possible (but blocking) way:

<script src=""></script>

Since day one of the social plugins though, it has always been possible to load this script asynchronously and it was guaranteed to work. Additionally, a few months ago the async snippet became the default when SDK snippet code is being generated by the various wizard-type configurators.

Here’s how an example configurator looks like:

The async code looks more complicated (it’s longer) than the traditional one, but it’s well worth it for the overall loading speed of the host page.

Before we inspect this snippet, let’s see what some of the goals were when designing a third-party provider snippet.

Design goals

  • The snippet should be small. Not necessarily measured in number of bytes, but overall it shouldn’t look intimidating.
  • Even though it’s small, it should be readable. So no minifying allowed.
  • It should work in “hostile” environments. You have no control over the host page. It may be a valid XTHML-strict page, it may be missing doctype, it may even be missing (or have more than one) <body>, <head>, <html> or any other tag.
  • The snippet should be copy-paste-friendly. In addition to being small that means it should just work, because people using this code may not even be developers. Or if developer, they may not necessarily have the time to read documentation. That also means that some people will paste that snippet of code many times on the same page, even though the JS needs to be loaded only once per page.
  • It should be unobtrusive to the host page, meaning it should leave no globals and other left overs, other than, of course, the included JavaScript.

The snippet

The snippet in the Facebook plugin configurators looks like so:

<script>(function(d, s, id) {
  var js, fjs = d.getElementsByTagName(s)[0];
  if (d.getElementById(id)) return;
  js = d.createElement(s); = id;
  js.src = "//";
  fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));</script>

Let’s see what’s going on here.

On the first and last line you see that the whole snippet is wrapped in an immediate (aka self-invoking, aka self-executing) function. This is to assure that any temporary variables remain in the local scope and don’t bleed into the host page’s global namespace.

On line 1 you can also see that the immediate function accepts three arguments, and these are supplied on the last line when the function is invoked. These arguments are shorthands to the document object and two strings, all of which are used more than once later in the function. Passing them as arguments is somewhat shorter than defining them in the body of the function. It also saves a line (vertical space), because the other option is something like:

<script>(function() {
  var js, fjs = d.getElementsByTagName(s)[0],
      d = document, s = 'script', id = 'facebook-jssdk';
  // the rest...

This would be one line longer (remember we want readable snippet, not overly long lines). Also the first and the last line will have “unused” space as they are somewhat short.

Having things like the repeating document assigned to a shorter d makes the whole snippet shorter and also probably marginally faster as d is local which is looked up faster than the global document.

Next we have:

var js, fjs = d.getElementsByTagName(s)[0];

This line declares a variable and finds the first available <script> element on the page. I’ll get to that in a second.

Line #3 checks if the script isn’t already on the page and if so, exits early as there’s nothing more to do:

if (d.getElementById(id)) return;

We only need the file once. This line prevents the script file from being included several times when people copy and paste this code multiple times on the same page. This is especially bad with a regular blocking script tag because the end result is something like (assuming a blog post type of page):

<script src="...all.js"></script>
<fb:like /> <!-- one like button at the top of the blog post -->
<script src="...all.js"></script>
<fb:like/> <!-- second like like button at the end of the post -->
<script src="...all.js"></script>
<fb:comments/> <!-- comments plugin after the article -->
<script src="...all.js"></script>
<fb:recommendations/> <!-- sidebar with recommendations plugin -->

This results in a duplicate JavaScript which is all kinds of bad, because some browsers may end up downloading the file several times.

Even if the JavaScript is asynchronous and even if the browser is smart enough not to reparse it, it will still need to re-execute it, in which case the script overwrites itself, redefining its functions and objects again and again. Highly undesirable.

So having the script with an id like 'facebook-jssdk' which is unlikely to clash with something on the host page, lets us check if the file has already been included. If that’s not the case we move on.

Next line creates a script element and assigns the id so we can check for it later:

js = d.createElement(s); = id;

Next line sets the source of the script:

js.src = "//";

Note that the protocol of the URL is missing. This means that the script will be loaded using the host page’s protocol. If the host page uses http://, the script will load faster, and if the page uses https:// there will be no mixed content security prompts.

Finally we append the newly created js element to the DOM of the host page and we’re done:

fjs.parentNode.insertBefore(js, fjs);

How does that work? Well, fjs is the first (f) JavaScript (js) element available on the page. We grabbed it earlier on line #2. We insert our new js> element right before the fjs. If, let’s say, the host page has a script element right after the body, then:

  • fjs is the script
  • fjs.parentNode is the body
  • our new script is inserted between the body and the old script

Appending alternatives

Why the trouble with the whole parentNode.insertBefore? There are simpler ways to add a node to the DOM tree, like appending to the <head> or to the <body> using appendChild(), however this is the way that is guaranteed to work in nearly all cases. Let’s see why the others fail.

Here is a common pattern:


Or a variation if document.head is available in newer browsers:

(document.head || document.getElementsByTagName('head')[0]).appendChild(js);

The problem is that you don’t control the markup of the host page. What if the page doesn’t have a head element? Will the browser create that node anyways? Turns out that most of the times, yes, but there are browsers (Opera 8, Andriod 1) that won’t create the head. Here is the test case by Steve Souders with the browserscope results.

What about the body? You gotta have the body. So you should be able to do:


I created browserscope test and couldn’t find a browser that will not create document.body. But there’s still the lovely “Operation Aborted” error which occurs in IE7 when the async snippet script element is nested and not a direct child of the body.

Last chance:


document.documentElement is the HTML element and its first child must be the head. Not necessarily, as it turns out. If there’s a comment following the HTML element, WebKits will give you the comment as the first child. Here’s an investigation with a test case.


Despite the possible alternatives, it appears that using the first available script node and insertBefore is the most resilient option. There’s always going to be at least one script node, even if that’s the script node of the snippet itself.

(Well, “always” is a strong word in web development. As @kangax pointed out once, you can have the snippet inside a <body onload="..."> and voila – magic! – a script without a script node)

What’s missing?

You may notice some things missing in this snippet that you may have seen in other code examples.

For instance there are none of:

js.async = true;
js.type = "text/javascript";
js.language = "JavaScript";

These are all defaults which don’t need to take up space, so they were omitted. Exception is the async in some earlier Firefox versions, but the script is already asynchronous and non-blocking enough anyway.

Same goes for the <script> tag itself. It’s an HTML5-valid bare bone tag with no type or language attributes.

First parties

This whole discussion was from the perspective of a third-party script provider. If you control the markup, some things might be different and easier. You can safely refer to the head because you know it’s there. You don’t have to check for duplicate insertions, because you’re only going to insert it once. So you may end up with something much simpler, such as:

<script>(function(d) {
  var js = d.createElement('script');
  js.src = "";
  (d.head || d.getElementsByTagName('head')[0]).appendChild(js);

This is all it takes when you control the host page.

Also we assumed all the time that whenever the script arrives, it just runs. But you may have different needs, for example call a specific function once the script is ready. In which case you need to listen to js.onload and js.onreadystatechange (example). In even more complex examples, you may want to load several scripts and guarantee their order of execution. At this point you may want to look into any of the available script loader projects such as LAB.js or head.js which are specially designed to solve these cases.

Parting words / on the shoulders of giants

It’s a little disturbing that we, the web developers, need to go to all these lengths to assure an asynchronous script execution (in a third-party environment or not). One day, with a few dead browsers behind us, we’ll just be able to say script async=true and it will just work. Meanwhile, I hope that this post will alleviate some of the pain as a resource to people who are yet to come to this problem and will hopefully save them some time.

Google AdSense folks have gone through a lot of trial and error while sharing with the community their progress, Mathias Bynens also wrote an inspirational critique of their snippet. Steve Souders has done research and written about this topic, also was probably among the first to use such a technique for loading JavaScript. There are writeups from Yahoo and many other on the topic. These are some of the giants that have helped in the search of the “perfect” snippet. Thank you!

(pssst, and if you see something that is less than perfect in the snippet, please speak up)


Stoyan (@stoyanstefanov) is a Facebook engineer, former Yahoo!, writer ("JavaScript Patterns", "Object-Oriented JavaScript"), speaker (JSConf, Velocity, Fronteers), toolmaker (, YSlow 2.0) and a guitar hero wannabe.

35 Responses to “The art and craft of the async snippet”

  1. Guypo

    Great post, Stoyan – good to see the step by step, and the logic behind it.

    One small question: Why not defer the loading of the script till after the page load? The Facebook Like button seems like a classic candidate for something that shouldn’t slow down your page.
    As per Aaron Peters’ recent blog post, dynamically added scripts still push out load events, and the download may contend with other page resources.

    At the very least, it might be useful to offer this to users who are comfortable stating their page doesn’t keep “loading” forever.

  2. sajal

    Ive noticed on firefox 7, if you have regular tags, the browser starts to pre-load them in advance, but if inserting it via dom.. it doesnt start loading until its been added.

    The js and css calls have an intentional sleep of 2 seconds to illustrate my point.

    I believe async is the ONLY way js should be loaded… but there is a tiny drawback, especially if the javascript functions are essential to the page and not value added features like social.

  3. GDR!

    Great post, Stoyan!

  4. JulienW

    about the script insertion, why could we not do this :




    (both of them are basically the same, because as I understand, if there is no referenceElement, then insertBefore just appends the element)

  5. IE’s Premature Execution Problem |

    [...] Adding a script to the DOM is pretty simple. Here’s a simple example taken from Stoyan’s recent Perf Calendar post: [...]

  6. IE’s Premature Execution Problem |

    [...] a script to the DOM is pretty simple. Here’s a simple example taken from Stoyan’s recent Perf Calendar post:     <pre escaped="true" lang="javascript" [...]

  7. piouPiouM

    You can reduce the size of the script of 4 characters by declaring the js and fjs variables at the signature of the anonymous function. Also, why not perform the test of presence of the script at first? You may avoid an unnecessary search in the DOM:

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

  8. Evgeny

    When referencing resources, it is probably best to use a schemaless URI like “//” instead of “”. As the provider of such snippets, you should definitely support https. And as a consumer you would definitely want to use https on secure pages, or else most browsers will show a warning about insecure assets on that page.

    Another point, is that as a webmaster that usually has several of these scripts (google analytics, facebook, kissmetrics, clicktale, a/b testing, etc…) it makes sense to add a for loop that will just iterate over an array of javascript URIs and thus save even more bytes. Also makes it much easier to just add “yet another javascript service” when required.

  9. Async JavaScript callbacks / Stoyan's

    [...] and you know gmail has been around, like, always). Then there was this and this and this and this. These days dynamic SCRIPT tags are something common, mainl because of it's non-blocking behavior [...]

  10. ionut popa

    this tehnique also works if you don’t want to block the onload event :

  11. Performance Calendar » SPOF: How we fixed a weird bug causing random users’ browsers to freeze

    [...] sharing of your content on Facebook. To implement the share button you can include the following snippet on your [...]

  12. Performance Calendar » The non-blocking script loader pattern

    [...] it using the regular JavaScript thread. If you’d like more details, Stoyan wrote about the async snippet in last year’s performance [...]

  13. Speed geek’s guide to Facebook buttons / Stoyan's

    [...] things first, you absolutely must load the SDK asynchronously. Or non-onload-blocking-asynchronously in an iframe. More on these two [...]

  14. Behind Facebook’s Faster Recommendations Plugin - AllFacebook

    [...] it was just partial content. This is because CSS is here early and all JS is out of the way (async loaded, also take a peek [...]

  15. The 20 best web performance links of Q4

    […] The art and craft of the async snippet Stoyan Stefanov examines the topic of asynchronous code “from the perspective of a third party – when you’re the third party, providing a snippet for other developers to include on their pages, be it an ad, a plugin, widget, visits counter, analytics, or anything else.” […]

  16. technology blog

    nice information i got here…great post admin…

  17. top 10 gadgets

    Today, while I waas aat work, my cousin stole my iPaad and tested to see
    if it cann survive a twenty five foot drop, juszt so
    she can be a youtube sensation. My iPad iss now broken andd she has 83 views.
    Iknow this is totally off topic but I hadd to share it with someone!

  18. Bernie

    Hi there, just became alert to your blog through Google, and found that it is truly informative.
    I am going to watch out for brussels. I’ll appreciate if you continue this in
    future. Lots of people will be benefited from your writing.

  19. Telecharger Tomb Raider

    Quality posts is the crucial to attract the visitors to pay a visit
    the site, that’s what this web site is providing.

    Stop by my webpage :: Telecharger Tomb Raider

  20. Beacon performance / Stoyan's

    […] Image().src is already async, but whatever the file where this JS code lives should be loaded asynchronously as […]

  21. green coffee bean max adelaide

    Great article. I’m facing many of these issues as well..


    How to kiss: comment embrasser une fille

    Kissing is’nt as hard as it would seem. Most think they do not
    know how but when the time will come they’re actually really great
    at it!

    A first kiss should usually be spontaneous but delicate, slow, and sweet.

    If your spouse kisses you first you may well open your lips a minor, but
    NO french kissing. It would ruin a initial kiss, comment embrasser and be sloppy.
    The idea, is really to press your lips up in opposition to your companions but not
    to much. Make certain your place is cozy as well, so your not in discomfort while

    If your Kissing your partner, comment embrasser perhaps commence by kissing
    him/her softly on the cheek, then when he/she seems to be
    at you, you can kiss them softly on the lips. comment embrasser

    And remember becoming by yourself might be far better for a 1st
    kiss. Issues may well not be so excellent with freinds watching…or jealous exes….
    comment embrasser une fille

    Remeber, remark embrasser une fille if the kiss was strange
    you too can usually chuckle it of safley and try out
    again next time.
    Si vous êtes déjà demandé comment embrasser votre
    partenaire, sans crainte d’être rejeté et la façon de rendre le baiser aussi passionné que possible, alors ne vous inquiétez pas.
    en suivant ce guide simple, vous aurez même la fille que vous êtes après penchant pour vous embrasser!

    un baiser peux vous faire du bien ou l’inverse, donc il est important de faire une bonne première
    impression quand il s’agit de baiser. ce guide va vous transformer à partir d’un ameteur à un prefessionnel en embrassant quelques minutes
    sans avoir besoin de pratique.

    vous pouvez consulter ce guide en ligne ou téléchargez-le gratuitement!
    obtener ce guide pour découvrir les ingrédients pour le
    baiser parfait!

    Feel free to surf to my site …

  23. sims 3 cheats

    Believe back to the initial time you ever read of sims 3 cheats.
    There are numerous aspects which influenced the growth of
    sims 3 cheats. Cited by numerous as the solitary most critical impact on publish modern micro eco compartmentalism, sims 3 cheats is
    showcasing more and a lot more in the ideals of the
    younger and upwardly mobile. Usually it is seen as equally a aid and
    a hinderence to the higher echelons of progressive services sector organisations, who are probably to form a major stronghold
    in the inescapable battle for hearts and minds.
    Though I would fairly be in bed I will now take a look at the
    main brings about of sims 3 cheats.
    As Reflected in classical mythology modern society is challenging.
    When blues legend ‘Bare Foot D’ remarked ‘awooooh eeee only my
    dawg understands me’ he borrowed significantly
    from sims 3 cheats. Far more a melody to societies dysfunctions than a parody of the
    self, sims 3 cheats irons out misconceptions from our consciousness.

    Some analysts have been tempted to disregard sims 3 cheats.
    I have not. If society has a favorite little one, it
    is sims 3 cheats.

    Contemporary politics owes significantly to the animal kingdom.
    Comparing the beliefs of the younger with the reality felt by their elders is like contrasting sims 3 cheats and ones possess
    picture of by themselves.
    It is often enlightening to take into account
    the words and phrases of jazz singer Achilles Lionel Forbes Dickinson ‘I
    really don’t think in ghosts, but I do think in democracy.’
    I couldn’t have set it better my self. When it will come to sims 3 cheats
    this is obviously real. To paraphrase, the estimate is declaring ‘sims 3 cheats wins votes.’ Basic as that.

    I hope, for our sake that sims 3 cheats will endure.

  24. toko online alat kesehatan dan alat kedokteran

    I have been surfing online more than 2 hours today,
    yet I never found any interesting article
    like yours. It is pretty worth enough for me. In my view, if all
    webmasters and bloggers made good content as you did,
    the net will be much more useful than ever before.

  25. Kam

    It’s awesome to payy a quick visit this web sit and reading the views
    of all colleagues on tthe topic of this post, while I am also eager of getting experience.

  26. Salomon Lab

    I like what you guys are up too. This kind of clever work and coverage!
    Keep up the terrific works guys I’ve you guys to my blogroll.

  27. Rhea

    Write more, thats all I have to say. Literally, it seems as though you relied on the video to
    make your point. You clearly know what youre talking about,
    why throw away your intelligence on just posting videos to
    your weblog when you could be giving us
    something enlightening to read?

  28. megapolis hack

    Society is often a man product. Whenever M L Darcy
    claimed ‘fevour will certainly spread’ your lover didn’t be aware that in the event a single really intends
    in order to ‘not appraise any publication by it is
    cover’, then one should understand a lot of textbooks.
    Although deviating from the usual may usually trigger unrest between kinds mates, megapolis cheats
    will be crunchy externally nevertheless soft
    in the middle.

    Status, Protection, Celebrity – megapolis cheats, many revolve with this in mind ‘golden fleece’.
    Putting it simple, folks including megapolis cheats.
    The world is pushed simply by present in addition to demand.

    All of us can largely always be working on the particular Inter-Spam
    style. Using exclusive attention in order to identify
    the particular part associated with megapolis cheats inside substantial
    composition which provided.

    My page; megapolis hack


    What’s up, just wanted to say, I loved this blog post. It
    was inspiring. Keep on posting!

  30. Zapatillas Salomon Ofertas

    Hi there, I discovered your web site by means of Google at
    the same time as searching for a similar matter, your web site came up, it appears great.
    I’ve bookmarked it in my google bookmarks.
    Hello there, simply become alert to your weblog thru Google, and found that it’s really informative.
    I am gonna watch out for brussels. I will be grateful should you proceed
    this in future. Many folks shall be benefited out of your
    writing. Cheers!

  31. Bali batik fabric

    Oh my goodness! Amazing article dude! Thank you, However I
    am having problems with your RSS. I don’t know why I am unable to subscribe to it.
    Is there anyone else having identical RSS issues? Anyone who knows the
    answer will you kindly respond? Thanx!!

  32. beli sepatu online

    Everything is very open with a very clear explanation of the challenges.
    It was definitely informative. Your site is useful. Thanks for sharing!

  33. isabel marant sneaker wedges

    isabel marant sneaker wedges Quando le borse sono congelati solido, togliere le scarpe e lasciarli
    scongelare per 20 minuti. (In questo modo sarà più facile rimuovere i
    sacchetti di plastica.) Togliere le scarpe acqua in eccesso
    e provare scarpe per le dimensioni. isabel
    marant sneaker wedges Calzature soddisfa l’occhio quando si è su una base quotidiana, controllare la parte
    superiore. Estelle perline realizzati con materiali di alta qualità
    che non danneggiano le gambe? Avere un materiale airpermeable o prodotto
    intermedio. buy isabel marant Se si considera l’acquisto di una macchina
    da cucire d’epoca, veterinaria e non lasciare che si guarda gradi
    attirare moduli di iscrizione. Fare qualche indagine sulla vettura che si stanno prendendo in considerazione e anche alcune tranquille
    gradi Come ogni domanda che si desidera cucire, quello che offre necessario avere le catene in
    auto. isabel marant shop Bella come il peccato Anaya modello
    giusto è molto più leggero è stato venduto direttamente
    ai clienti di distributori. Albergo Pertanto, Div lei è felice di essere invitato a cacciatori di Kim mantenuto giuste haiku tempi del Nuovo Studios.
    isabel marant shop Il prezzo di una caccia al fagiano non guidato su un caccia New Jersey preservare
    è di circa $ 150 per cacciatore per la caccia threeto
    quattro ore. La maggior parte Hunting Preserve ha un limite di quattro fagiano per $ 150 albero.

    buy isabel marant Formaggio americano. Detti fette di formaggio
    precedentemente trattati separatamente e sostituite, Kitty Corner, un elegante pila un’azione facilmente afferrare
    appena sono sulla griglia. isabel marant sneaker wedges Il numero di tartarughe liuto sulla spiaggia tropicale ha raccolto in
    modo spettacolare, con circa 500 femmine nido ogni sera durante l’alta stagione a maggio e giugno, il 800 metro (875 metri) sulla spiaggia.
    Gli scienziati ora ritengono che la spiaggia del Grand Riviere,
    lungo un fiume che sfocia nell’Oceano Atlantico, la più densamente nidificati invece liuto nel mondo..
    buy isabel marant Asheville, Carolina del Nord durante una sosta in giro per
    la prova di tenuta, Ford, Chrysler 300 AWD per il gusto di confronto fornita
    a noi e dentro di esso, a piedi, e la distribuzione del potere
    in quasi ogni aspetto, comprese ovale blu preferito, mentre Hemi il
    suono Volevo bottiglia e un iniziale ingegneri Ford come un punto di
    smaltimento. Allo stesso modo, un minimo di cambiamenti in una varietà di
    giardino Toro design esterno tranquilla sembra la maggior parte sono costruiti su SHO.
    isabel marant sneaker wedges isabel marant shop

  34. download photoshop

    We’re a group a group of volunteers and starting
    a new scheme in our community. Your website offered us with helpful helpful and paintings
    on . You made ​​an impressive task and our all
    the community be grateful to you .
    Unquestionably Account which you said . Your
    favorite reason seemed to be at the internet simple thing to
    keep in mind of . I tell you , i certainly annoyed at the
    same time while think issues clear that just
    do not recognize about . You controlled
    well as defined everything managed to hit the nail on the top
    without having side effect , others could take a signal.

    Will probably be back to get more. Thanks

    Feel free to surf to my site – download photoshop

  35. hack deer hunter 2014

    We are a group a group of volunteers and starting
    a brand new scheme in our community. Your web site provided us with valuable
    and work on . You have made ​​an impressive
    process and our whole neighborhood can be thankful
    to you .
    Undeniably believe that you said . Your favorite reason
    appeared to be at the web easy thing to take note of .
    I tell you , i certainly annoyed think issues
    clear that not realize about . You controlled and out
    on all managed to hit the nail on the top without having side-effects ,
    other folks cAN could take a signal. Will probably
    be again to get more. Thanks

    Also visit my homepage: hack deer hunter 2014

Leave a Reply

You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>
And here's a tool to convert HTML entities