Feature detection for jQuery 2

Orde Saunders' avatarPublished: by Orde Saunders

With the release of jQuery 2.0 support for versions of Internet Explorer prior to version 9 will be dropped. The recommendation on the jQuery website is to include version 2 with conditional comments but this will not work for legacy browsers that aren't IE. I haven't been able to find information of what features are required for jQuery 2 that are not supported in legacy IE so have done some investigation and found a method to include it that uses feature detection rather than conditional comments.

Finding the requirements

As I couldn't find any published requirements for jQuery 2 I built a simple test page that included the beta 1 and checked to see what errors were thrown when loaded in IE7 and IE8.

IE7

IE7 falls over as there is no native JSON parser:

'JSON' is undefined
jquery2.js, line 349 character 1

As it is possible to load a JSON parser I did so and tried again to see what the next error was:

Object doesn't support property or method 'addEventListener'
jquery2.js, line 791 character 7

IE8

As IE8 does have a native JSON parser it also fell down on a lack of addEventListner.

SCRIPT438: Object doesn't support property or method 'addEventListener'
jquery2.js, line 791 character 7

Additional requirements

Whilst it does not trigger an error in IE7 or IE8, document.querySelectorAll is used by jQuery and if this is lacking element selection will be significantly slower. It is not supported in IE7, IE8 only supports CSS2 selectors and the source for jQuery 1.9 contains code to work round a lack of support for a native query selector so I have treated it as a requirement for jQuery 2.

Including the scripts

As we now have a feature detectable requirement for the library we can now include it if it is supported. There are two methods for this - synchronous and asynchronous - and you will need to choose which method you require based on you individual circumstances.

Synchronous

Including a script via JavaScript is one of the few non-evil uses of document.write:

<script>
if (typeof JSON !== 'undefined' && 'querySelector' in document && 'addEventListener' in window) {
  document.write('<script src="[path to jQuery 2]"><\/script>')
}
</script>

Asynchronous

Including a script asynchronously is achieved via DOM insertion and, as we need to use variables, we do it using an immediately invoked anonymous function:

<script>
(function () {
  var s, s0, js = '[path to jQuery 2]';
  if ('querySelector' in document && 'addEventListener' in window) {
    s = document.createElement('script');
    s.type = 'text/javascript';
    s.async = true;
    s.src = js;
    s0 = document.getElementsByTagName('script')[0];
    s0.parentNode.insertBefore(s, s0);
  }
}());
</script>

Providing a fall-back

Unless you're doing it wrong, you're building your websites using progressive enhancement so JavaScript is not a requirement which means that only including jQuery for supported browsers isn't going to cause a problem for unsupported browsers. However, if you wish to provide support for legacy browsers by using jQuery 1.9 but want to reward modern browsers with the faster version 2 then it's possible to do this as well. Again this can be done both synchronously and asynchronously.

Note: I really wouldn't advise including two versions of jQuery like this, it will double your testing and debuging workload for very little gain. If you want to support older browsers then I strongly advise you to only include jQuery 1.9. However, if you do want to include both then this method is much better than using conditional comments.

Synchronous

<script>
(function () {
  var js;
  if (typeof JSON !== 'undefined' && 'querySelector' in document && 'addEventListener' in window) {
    js = '[path to jQuery 2]';
  } else {
    js = '[path to jQuery 1.9]';
  }
  document.write('<script src="' + js + '"><\/script>');
}());
</script>

Asynchronous

<script>
(function () {
  var s, s0, js;
  if (typeof JSON !== 'undefined' && 'querySelector' in document && 'addEventListener' in window) {
    js = '[path to jQuery 2]';
  } else {
    js = '[path to jQuery 1.9]';
  }
  s = document.createElement('script');
  s.type = 'text/javascript';
  s.async = true;
  s.src = js;
  s0 = document.getElementsByTagName('script')[0];
  s0.parentNode.insertBefore(s, s0);
}());
</script>