Loading Scripts – Sync or Async

March 12, 2012

In many programming languages we have the concept of including files/scripts in a project. This means that the compiler or the interpreter needs to fetch and read another file. This is one of the building blocks of modern programming.

In JavaScript we don’t have an actual include but we can add scripts to the DOM to make sure they are added to the page. Sometimes scripts can be depended, so one script is using some code which was defined in another. This could lead to some problems if we don’t understand how browsers loads scripts.

Static Scripts

First lets define two scripts which we will use in our examples.

script1.php


<?php
    sleep(3);
    echo "var obj1 = { a : '1' };";
?>

This script is defining an object called obj1. I’ve added a sleep of 3 seconds to make sure it will take some time for the page to download the script.

script2.js


alert( obj1.a );

This script is only trying to alert the object which was defined in script1.

In the static example we add these scripts in the right order in the head or in the body like so:


    <footer> some copyright .... </footer>
    <script src="script1.php"></script>
    <script src="script2.js"></script>
</body>
</html>

When the browser see this it will try to load all the script asynchronously but will execute them synchronously according to the order that they were defined.

So in our case the browser will download script2 before it loads script1, but will execute script2 only after script1 was loaded. This is exactly how we expect it to be. Things get a little different when we are using the dynamic scripts approach.

Dynamic Scripts

In this case we load the scripts using Javascript like so:


var body = document.getElementsByTagName("body")[0];
var s1 = document.createElement("script");
s1.src = "script1.php";
body.appendChild(s1);
var s2 = document.createElement("script");
s2.src = "script2.js";
body.appendChild(s2);           

In this case the same code will be executed differently on different browsers.

Firefox and Chrome will see that in the same CPU cycle we are adding two scripts to the DOM and they will keep the synchronous execution dependency between them. So in Firefox and Chrome executing this code will work, since the browser will execute them in the right order.

in IE (at least IE9) it is implemented differently. IE doesn’t keep this synchronously execution dependency between the two files and execute each file whenever it is loaded. This will cause an error in run time since script2 will be executed before script1 and the object was not defined yet.

To make the difference more clear lets break the CPU cycle like so:


var body = document.getElementsByTagName("body")[0];
var s1 = document.createElement("script");
s1.src = "script1.php";
body.appendChild(s1);
setTimeout( function(){
    var s2 = document.createElement("script");
    s2.src = "script2.js";
    body.appendChild(s2);  }, 1 );

Since the second script is being executed in a different CPU cycle Firefox and Chrome can’t keep the dependency between them anymore and each script is executed when it is loaded, which will result an error in run time.

HTML5 Async Attribute

One interesting feature HTML5 introduced is the ability to control how script will be executed by the browser. If we set this attribute to true on the script tag/element it will tell the browser to executed the script immediately when its loaded. This was introduced in order to allow developers to better control and optimize the loading of scripts. So if i know i need to load many scripts that are not depended on each other, it is better to set this flag to true to speed the loading of the page and improve the user experience.

Unfortunately this attribute is not supported by IE9.

For more information about this new feature you can read in IE test drive, or MDN

Summary

As long as you have static script loading you can control the dependency. If you want to optimize the loading using the async attribute you need to remember that its not being supported by all browser. If you are loading your script in a dynamic way and you have some dependencies in your script i would suggest the following:

  • Merge – if this is possible in your project, merge these files into one file and load them in one call. This is an optimization rule that you should try to do regardless to this problem.
  • Server side script building – if you need to add scripts dynamically according to some conditions, you could also do that on the server side using PHP for example.

 

Bookmark and Share
Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • E-mail this story to a friend!
  • FriendFeed
  • LinkedIn
  • StumbleUpon
  • Twitter

tags: , ,
posted in Blog by Amir Harel

4 Comments to "Loading Scripts – Sync or Async"

  1. ge wrote:

    Great article. I’m a fan of dynamic scripts. Not only will it blocks onload from triggering
    until the referenced script is fully loaded. Doing so prevent caching
    of the JS scripts and if you have your JS script doing some DOM
    manipulation to hide certain elements from the users if JS is enabled,
    then they might see those elements loaded first before any action
    happens to them. Kind of a strange flickering effect.

  2. ge wrote:

     i meant to say “NOT a fan..”

  3. Amir Harel wrote:

     i agree that dynamic scripting can create some annoying behaviors but most of them can be solve with hacks. There are situations when you must have dynamic scripting like long jsonp to support cross domian and  cross browser real time communication.

  4. Amir wrote:

    very interesting

 
Powered by Wordpress and MySQL. Theme by openark.org