Thursday, July 24th, 2008

Getting around the blocking of script

Category: JavaScript, Performance, Yahoo!

<p>Stoyan Stefanov has a post that discusses the issues with browsers blocking on script tags.

He discusses the general problem and how YUI has a helper for it by using onreadystatechange and onload:

javascript
< view plain text >
  1. var myHandler = {
  2.     onSuccess: function(){
  3.         alert(':))');
  4.     },
  5.     onFailure: function(){
  6.         alert(':((');
  7.     }
  8. };
  9.  
  10. var urls = ['1.js', '2.js', '3.js'];
  11. YAHOO.util.Get.script(urls, myHandler);

The game is changing though, as he mentions:

Safari and IE8 are already changing the way scripts are getting loaded. Their idea is to download the scripts in parallel, but execute them in the sequence they’re found on the page. It’s likely that one day this blocking problem will become negligible, because only a few users will be using IE7 or lower and FF3 or lower. Until then, a dynamic script tag is an easy way around the problem.

Danny Thorpe wrote some comments and the issue with Safari:

This works great for Firefox and IE, but fails completely in the Safari browser. Safari doesn’t implement onLoad notifications for script tags. This forces you to abandon the onLoad technique and instead use the technique of embedding something at the end of each script file to signal when the file has been loaded.

The script libraries for the Windows Live sites use this technique – every source file contains a function call at the bottom that tells a central notifier that it has been loaded. Other code can ask the notifier to signal them when a file or set of files have been loaded. This works in all browsers without relying on diverging browser idiosyncrasies.

Related Content:

6 Comments »

Comments feed TrackBack URI

I use a similar “suffix” technique by putting something at the end of my scripts for load detection… However, the problem I’ve found with each loaded script having to call some central “callback” function to notify that they’ve been loaded is that there’s always the question of what to do with the first script, the one that defines that callback function for all the rest of them to use. And what if that guy doesn’t get loaded before another one does? Then the callback call fails!
So, instead, every one of my scripts silently define a dummy/empty function at the very last line called something like “module_ready()”. This function has no code in it and does nothing, and only costs like a few characters… but then, in my main code, whatever has called to load this script dynamically, it sets up a setInterval loop which has a try/catch block in it to try and call that module_ready function over and over… if the script isn’t fully loaded and parsed yet, an “error” is thrown on this call and caught, and the timer continues again… if it succeeds, the timer is cleared and the library is ready to go!

Comment by shadedecho — July 24, 2008

just a callback…

Comment by KKFC — July 24, 2008

I’ve written a little library for exactly this purpose some time ago. It doesn’t need any thirdparty libs which is a big plus in my book, but I haven’t really used it since I released it so it is essentially untested. It works through XMLHttpRequest and should therefore work in any browser that supports that, at the very least IE 7/8, FF 2/3, Opera 9 and Safari 3.

http://www.tapper-ware.net/devel/js/csi/csi.htm

Comment by Hans Schmucker — July 24, 2008

@shadedecho: You’re working way too hard at that. :-)

There is a much simpler solution. Your first script, the one that defines the “ready” callback, is the one that loads the rest of the scripts.

IOW, instead of this:

HTML dynamically loads scripta.js, scriptb.js, and scriptc.js, where scripta.js defines a callback for scriptb.js and scriptc.js.

Do this:

HTML loads scripta.js either dynamically or through a script tag – it doesn’t matter which. scripta.js defines a callback function and then dynamically loads scriptb.js and script.js.

See how the first approach requires a complicated solution, while the second one solves it naturally?

Comment by MG — July 24, 2008

onload fires in Safari 3, it doesn’t in Safari < 3. Like I said in the article, if you want a truly cross-browser solution, you need to add a simple variable or an array hold a list of all included files.

YUI Get does everything possible (tries a timeout for Safari < 3) to ensure the script is loaded.

Comment by stoyan — July 24, 2008

When you are using Safari <3 which does not fire an onload event, there is a workaround to simulate it : the idea is as it’s sequencially executing script tags, you have to had a script tag after the one you want to load, and call the callback from it.

see http://bug.archetypejs.org/jira/browse/AJF-27

Comment by temsa — July 25, 2008

Leave a comment

You must be logged in to post a comment.