views:

48

answers:

3

I've been working on a bit of JavaScript code that, under certain conditions, lazy-loads a couple of different libraries (Clicky Web Analytics and the Sizzle selector engine).

This script is downloaded millions of times per day, so performance optimization is a major concern. To date, I've employed a couple of flags like script_loading and script_loaded to try to ensure that I don't load either library more than once (by "load," I mean requesting the scripts after page load by inserting a <script> element into the DOM).

My question is: Rather than rely on these flags, which have gotten a little unwieldy and hard to follow in my code (think callbacks and all of the pitfalls of asynchronous code), is it cross-browser safe (i.e., back to IE 6) and not detrimental to performance to just call a simple function to insert a <script> element whenever I reach a code branch that needs one of these libraries?

The latter would still ensure that I only load either library when I need it, and would also simplify and reduce the weight of my code base, but I need to be absolutely sure that this won't result in additional, unnecessary browser requests.

My hunch is that appending a <script> element multiple times won't be harmful, as I assume browsers should recognize a duplicate src URL and rely on a local cached copy. But, you know what happens when we assume...

I'm hoping that someone is familiar enough with the behavior of various modern (and not-so-modern, such as IE 6) browsers to be able to speak to what will happen in this case.

In the meantime, I'll write a test to try to answer this first-hand. My hesitation is just that this may be difficult and cumbersome to verify with certainty in every browser that my script is expected to support.

Thanks in advance for any help and/or input!

+1  A: 

Got an alternative solution.

At the point where you insert the new script element in the DOM, could you not do a quick scan of existing script elements to see if there is another one with the same src? If there is, don't insert another?

Javascript code on the same page can't run multithreaded, so you won't get any race conditions in the middle of this or anything.

Otherwise you are just relying on the caching behaviour of current browsers (and HTTP proxies).

thomasrutter
Thanks, thomasrutter! Yours seems like a feasible approach, but I'm concerned about the performance impact of all of that DOM traversal. My script is loaded on some very large and complex pages, and it seems like running `document.getElementsByTagName('script')` every time is likely to have a negative effect on performance. My current approach complicates the code, but only has to check a boolean variable or two each time; my proposed approach would allow me to cache a `document.getElementsByTagName('head')[0]` and then just append a single script node to that each time. Thoughts?
Bungle
Also wanted to mention that you have a good point about relying on the caching behavior of current browsers/proxies. My proposed approach could have a very negative performance impact for any users with browser caching disabled.
Bungle
About the performance aspect - I probably wouldn't worry too much, unless you have 200+ script elements on a page I suppose. It's no so much traversal as relying on the getElementsByTagName() function to implemented efficiently on whatever browser. If you're really concerned you could maintain your own list in the form of an array of which scripts have been previously loaded (an approach I've taken in a JS framework of mine).
thomasrutter
A: 

The page is processed as a stream. If you load the same script multiple times, it will be run every time it is included. Obviously, due to the browser cache, it will be requested from the server only once.

I would stay away from this approach of inserting script tags for the same script multiple times.

The way I solve this problem is to have a "test" function for every script to see if it is loaded. E.g. for sizzle this would be "function() { return !!window['Sizzle']; }". The script tag is only inserted if the test function returns false.

Joeri Sebrechts
Thanks, Joeri! Your test function approach sounds worth looking into. I'll review my code to see if I can abstract all of the checks that I do into a central function for a more modular approach.
Bungle
A: 

Each time you add a script to your page,even if it has the same src the browser may found it on the local cache or ask the server if the content is changed.

Using a variable to check if the script is included is a good way to reduce loading and it's very simple: for example this may works for you:

var LOADED_JS=Object();
function js_isIncluded(name){//returns true if the js is already loaded
   return LOADED_JS[name]!==undefined;
}
function include_js(name){
    if(!js_isIncluded(name)){
        YOUR_LAZY_LOADING_FUNCTION(name);
        LOADED_JS[name]=true;
    }
}

you can also get all script elements and check the src,my solution is better because it hase the speed and simplicity of an hash array and the script src has an absolute path even if you set it with a relative path.
you may also want to init the array with the scripts normally loaded(without lazy loading)on the page init to avoid double request.

Plokko