Skip to content

Instantly share code, notes, and snippets.

@tobsn
Created December 10, 2010 19:50
Show Gist options
  • Save tobsn/736705 to your computer and use it in GitHub Desktop.
Save tobsn/736705 to your computer and use it in GitHub Desktop.
there are many problems when you act as third party that offers a javascript file and you want to use jquery - this solved all of my problems. the little function checks if jquery is already embedded, includes it and waits until its loaded if its missing
(function(j,q,u,e,r,y,R,o,x){try{o=jQuery;if(o&&(!R||(R&&o.fn.jquery==R))){x=true}}catch(er){}if(!x||(R&&o.fn.jquery!=R)){(q=j.createElement(q)).type='text/javascript';if(r){q.async=true}q.src='//ajax.googleapis.com/ajax/libs/jquery/'+(R||1)+'/jquery.min.js';u=j.getElementsByTagName(u)[0];q.onload=q.onreadystatechange=(function(){if(!e&&(!this.readyState||this.readyState=='loaded'||this.readyState=='complete')){e=true;x=jQuery;jQuery.noConflict(true)(function(){y(x)});q.onload=q.onreadystatechange=null;u.removeChild(q)}});u.appendChild(q)}else{y(o)}})(document,'script','head',false,false,(function($){$(function(){
/* code goes here */
console.log($.fn.jquery);
})}));
// readable:
(function (j, q, u, e, r, y, R, o, x ) {
// IE8 undefined crash fix
try {
// check if we can assign jQuery
o=jQuery;
// if jquery is defined and version is not set or version is set and matches the existing one
if( o && ( !R || ( R && o.fn.jquery == R ) ) ) {
x = true;
}
}
catch(er) {}
// if jquery isnt set or version is defined and its not matching
if( !x || ( R && o.fn.jquery != R ) ) {
(q = j.createElement(q)).type = 'text/javascript';
if (r) { q.async = true; }
// dont need http|https - /1/ means latest 1.x version
q.src = '//ajax.googleapis.com/ajax/libs/jquery/'+(R||1)+'/jquery.min.js';
u = j.getElementsByTagName(u)[0];
// onload event for callback
q.onload = q.onreadystatechange = (function () {
// first fire when completely loaded and parsed & check if this happened before
if (!e && (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete')) {
e = true;
// copy space into new var, release control and execute callbacks with passed in own version of jQ
x = jQuery;
jQuery.noConflict(true)(function(){y(x);});
// IE memory leak protection
q.onload = q.onreadystatechange = null;
u.removeChild(q);
}
});
u.appendChild(q);
}
else {
// jquery is already there and version matches or we dont care about version
y( o );
}
// async callback
})(document, 'script', 'head', false, false, (function ($) {
$(function(){
/* code goes here */
console.log( $.fn.jquery );
});
// version if needed - optional (see compressed version above)
}),'1.4.2');
@SlexAxton
Copy link

You aren't running any handlers, etc. It's pretty hard thing to see right away.

Here is the test I ran with asynchronous injection of scripts and their subsequent callback handlers. This is an easier example to show that this is possible. It applies to all scripts, including jQuery. I'm using labjs for the dynamic script injection, but that doesn't matter. I also tested with direct onload expandos, etc, and the results were the same.

http://slexaxton.com/jsloadtests/ (you may have to load it a few times, with a hard refresh, to see a failure in an IE, but it's pretty common).

In every browser that's not IE8 and below, it should read '# executed' followed by the same '# loaded.' - The order of the scripts themselves don't much matter, but the fact that scripts can execute between the execution of an injected script and the execution of their onload callbacks is the alarming thing.

A Screenshot in IE8 in case you/someone doesn't have it: http://slexaxton.com/pix/7b5c.png (notice 4-6-4 order)

vs.

A Screenshot in Chrome Dev channel (9.xx): http://slexaxton.com/pix/faee.png (all numbers load in pairs - aka an atomic callback)

Hope that helps.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment