Let me start by saying that this is not a "break-up with jQuery post" - in fact, I like jQuery and know that we all owe it a great debt. jQuery does great things for normalising behaviours, fixing bugs and providing a somewhat simpler syntax, but we need to start relying on a lot less.

With the explosion of mobile and low-powered devices, it's becoming more and more apparent that front-end #perfmatters. We need to be considerate of the impact that our web solutions have on a user's battery, the speed on which the DOM is manipulated and pages are rendered to the screen. While there are many facets of web performance optimisation, I'd like to focus on a simple one that every developer who uses jQuery can easily achieve: use native "vanilla" JavaScript properties and methods where suitable.

If you read through jQuery's source, you'll see that its syntax is mostly just a middle man for what JavaScript supports natively. But their methods often also have additional logic to traverse, which gets or sets depending on the number of arguments. For example: .attr('href') gets the link's href, and .attr('href', 'http://foo.com) sets it. In native JavaScript, there are two distinct methods: .getAttribute() and .setAttribute(), which I personally find clearer to understand.

It's this middle man approach that offers an unnecessary overhead.

Take the following two code snippets, which demonstrate how you could get and set particular attributes on links and inputs using both jQuery and vanilla JavaScript:

jQuery

  $jqueryLinks.each(function(index) {
  var $this = $(this);
  var href = $this.attr('href');
  var id = $this.attr('id');
  $this.attr('data-id', id);
  $this.css('color', 'red');
  $this.html('Replaced jQuery Link ' + (index + 1));
});

$jqueryInputs.each(function(index) {
  var $this = $(this);
  var name = $this.attr('name');
  var value = $this.attr('value');
  var type = $this.attr('type');
  $this.attr('data-value', value);
  $this.css('background-color', 'yellow');
  $this.val('Replaced jQuery Input ' + (index + 1));
});

You can see that the jQuery versions use .attr(), .css(), .val() and .html() - functions we've all use a million times before. They're familiar and consistent.

Vanilla JavaScript

  $vanillaLinks.each(function(index) {
  var $this = $(this);
  var href = this.href;
  var id = this.id;
  this.setAttribute('data-id', id);
  this.style.color = 'red';
  $this[0].innerHTML = 'Replaced Vanilla Link ' + (index + 1);
});

$vanillaInputs.each(function(index) {
  var $this = $(this);
  var name = this.name;
  var value = this.value;
  var type = this.getAttribute('type');
  this.setAttribute('data-value', value);
  this.style.backgroundColor = 'yellow';
  $this[0].value = 'Replaced Vanilla Input ' + (index + 1);
});

The vanilla version uses the elements' native properties (href, id, getAttribute() etc) to achieve exactly the same result, but ~70% faster!. You can see for yourself in my jsPerf test.

So how do you get to learn which properties are available for a particular element? The simplest method I use is to select an element in Firebug or Chrome's Dev Tools, switch to the console and type $0.; this will then present a list of all the native properties and methods available. In Firebug, you can also right click an element in the HTML or Console panels, and "Inspect in DOM Panel", which provides a pretty, formatted tree of everything available and their values. It's awesome.

See that $this[0].value line in the final example? Basically, a jQuery selector returns an object, so if you already have a stored selector, you can access its native properties with the index of the element in the selector. In an '.each()' loop, which is where probably you'd use this technique most, it will always be 0 because it's the first and only element for that loop's pass.

Also, note that I'm storing a variable to the current element as $this. Technically, I didn't need to do it in the vanilla example (it was just used for consistent benchmarking), but if you use jQuery to "touch" an element more than once, you should store a reference to it. It's obviously faster than multiple $(this)s. Oh, and never select from the DOM multiple times with, for example $('#foo').addClass('bar'); $('#foo').height('auto'); because that's bad for performance, too.

Notice that in both examples, I'm utilising jQuery's .each() method to iterate over the selected elements. This is partly for un-biased benchmarking, but also because it's a nice, simple way to loop through them. jQuery makes sense here. It also makes sense when adding and removing cross-browser event handlers with .on() and .off() respectively, adding and removing classes, ajax, chaining operations and more.

It's worth noting that properties like .href can both get and set a value, too; they're a shorthand of sorts for .get/setAttribute(). It's also worth noting that .get/setAttribute('href') is marginally faster than .href, but for these kind of micro-optimisations, you'll also need to consider the final, minified, gzipped payload size; it's a balancing act.

And finally, it's important to know that you may not always want to use native property. For example, serializing a form for posting with jQuery's .ajax() method will actually use what's stored in .val(), not what's in the native .value.

So, like I said at the beginning, use jQuery for what it's good for, but try and use it a bit smarter.


4,735 7 23