4

imagine the following setup: A page that has an old jQuery version (say 1.5.2) - that I have no control over - loads a Javascript file from my servers that also need jQuery, but a more recent version. (for example 1.8.3) Now my script tries to do the following:

var script = document.createElement("script");
script.setAttribute("type", "text/javascript");
script.setAttribute("src", "http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js");
script.onreadystatechange = function() { // IE
  if (script.readyState === "complete" || script.readyState === "loaded") {
    ready();
  }
};
script.onload = function() { // other browsers
  ready();
};
(document.getElementsByTagName("head")[0] || document.documentElement).appendChild(script);

The ready function then checks if $ has the correct version of jQuery and if it does, it binds that jQuery instance to another variable and returns $ to the original jQuery version, via newjQuery = window.jQuery.noConflict(true);.

Now this works all fine and dandy and there is no (outside) code execution happening between loading "my" jQuery version and restoring $ to "their" jQuery version - at least on Chrome, Firefox, etc. Where this approach fails is Internet Explorer, which for some reason processes at least 1 more "tick" of Javascript code that might be running in parallel. This tends to mess up code that is not compatible with "my" jQuery version and happens to get executed in the 5ms where IE has not executed the ready event yet.

Here's an example fiddle: http://jsfiddle.net/w5pPp/3/

In the fiddle, I test for the currently bound jQuery version every 10ms. Only in IE9 there sometimes is a short time span where $ refers to "my" jQuery, as indicated by a "THIS SHOULD NOT HAPPEN" log.

Now my question is this: What would be the best solution to load "my" jQuery version into its own variable without causing any problems in the execution of the page code in the short time span where it overwrites "their" jQuery before calling noConflict?

S.B.
  • 2,920
  • 1
  • 17
  • 25
  • Do you only not have control over the *version* of "my" jQuery? Would it be at all possible to put both yours and the loaded versions in no conflict mode and reference each one separately (as in [this answer](http://stackoverflow.com/a/1566644/74757))? I didn't know this until I look at that thread, but if two versions are loaded, the second takes over `$`, but a backup of the original remains as `_$`. Maybe you can take advantage of that. – Cᴏʀʏ Mar 28 '13 at 14:12
  • @Cory I only have control over "my" jQuery and not over "their" jQuery. This means that if I move "their" jQuery to a different variable name, their code will break. `$` has to be "their" jQuery while "my" jQuery could be associated with any variable I want. – S.B. Mar 28 '13 at 14:27
  • Are you hosting/can you host your newer jQuery file? As then you can just edit the jQuery code to use a different name, it's a one line change. – mattmanser Mar 28 '13 at 15:18
  • I have considered hosting my own jQuery version, but this comes at a price: cache hits will be much less than with Google CDN hosted jQuery versions and I have to update the custom jQuery library whenever I want to switch to a new version. It's kind of a last resort for me, so if there is a better solution, I would prefer not doing this. – S.B. Mar 28 '13 at 16:25
  • possible duplicate of [Can I use multiple versions of jQuery on the same page?](http://stackoverflow.com/questions/1566595/can-i-use-multiple-versions-of-jquery-on-the-same-page) – Troy Alford Mar 28 '13 at 18:29
  • @TroyAlford not really, since I am already using noConflict and talking about a race condition with it in IE browsers. – S.B. Mar 28 '13 at 22:33
  • Ahh... let me update my answer. – Troy Alford Mar 28 '13 at 22:35

1 Answers1

1

When you load your version of jQuery, try the following:

<!-- load your jQuery version -->
<script type="text/javascript" src="http://example.com/jquery-1.9.1.js"></script>
<script type="text/javascript">
    var $_mine = $.noConflict(true);
</script>

<!-- initialize their scripts -->
<script type="text/javascript" src="http://example.com/their-jquery.js"></script>
<script type="text/javascript" src="http://example.com/their-script.js"></script>

This should result in you having $_mine available to utilize your version of jQuery, without conflicting with the other script, and its use of $, which will refer to the outdated version.

As mentioned in commentary above, refer to Can I use multiple versions of jQuery on the same page? for further details / information / examples.

EDIT:

It sounds as if this won't resolve your issue, based on the comments above. In this case, my suspicion is that you are actually seeing an issue of asynchronicity of download speeds between your cdn's. Try loading both your AND their version of jQuery the same way, one after the other.

In other words:

function loadScript(variable_name, script_url) {
    var script = document.createElement("script");
    script.setAttribute("type", "text/javascript");
    script.setAttribute("src", script_url);
    script.onload = function() {
        if (variable_name != undefined) {
            window[variable_name] = jQuery.noConflict(true);
            console.log("after attach: " + window[variable_name].fn.jquery);
        }
    };
    (document.getElementsByTagName("head")[0] || document.documentElement).appendChild(script);
};

loadScript('newjQuery', 'http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js');
loadScript('$', 'http://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js');
//loadScript(undefined, 'http://example.com/some/dependent/script/requiring-1.5.2.js');

Here is a working jsFiddle which shows this method working: http://jsfiddle.net/w5pPp/5/

The trick is loading the two items sequentially, and loading the dependencies after the jQuery versions are in place.

Community
  • 1
  • 1
Troy Alford
  • 26,660
  • 10
  • 64
  • 82
  • 1
    Good idea, actually. Will have to try that, though I would have to make loading their jQuery dynamically based on the version they're using. Thanks, Troy, I will get back to you once I tested it. – S.B. Apr 02 '13 at 07:54