jQuery Performance : building DOM elements

This is the third post regarding jQuery performance, it’s not technically jQuery performance, as I am not comparing two different ways of doing something with just jQuery, but more comparing jQuery over native JavaScript methods, mainly showing just because you are using jQuery does not mean you have to use it for everything.

As jQuery is JavaScript, and a very nice way of interacting with the DOM, and handles a lot of the cross browser issues for you, I see a lot of case’s where jQuery is over used and can be a performance issue on an application. Maybe for your average Joe who’s doing some simple bits and bobs to make their site stand out, this may not be an issue. But me being me, I love performance metrics, and testing different ways of doing things. I am always questioning asking: WHY?

The code

If you are working on web applications or something relatively big and generally something that involves an AJAX call to fetch data from a remote source. Chances are you are more than likely going to have to build some DOM elements with the data you have just fetched. Sounds simple enough.

For the purpose of this article we are not hitting any remote services to get our data, but we are building a table for users, that has 4 columns, and 50 rows. We have a name, company, admin, and actions column. Also in this example we are inserting the same data for each row of the table.
You maybe thinking, this is not going to show up much in the way of performance, but hold onto your hat and keep reading!

Example 1 – jQuery

The first example is using all jQuery methods to build all the DOM elements, and add them to variables then append the entire new row to the table.

    for ( var i=0; i < rows; i++ ) {

      var $newRow = $(‘<tr />’);

      var $fRow = $newRow.append($(‘<td />’).text(‘Jim’));

      var $sRow = $newRow.append($(‘<td />’).text(‘Testing’));

      var $tRow = $newRow.append($(‘<td />’).text(‘No’));

      var $foRow = $newRow.append($(‘<td />’).text(‘Delete’));

      $table.append($newRow);

    }

Exampe 2 – JavaScript Variable with jQuery append

The second example uses one jQuery call to append the HTML string I have built up in a variable using standard HTML markup.

    for ( var i=0; i < rows; i++ ) {

      row = ‘<tr><td>Jim</td>’

      row += ‘<td>Testing</td>’

      row += ‘<td>No</td>’

      row += ‘<td>Delete</td></tr>’

      $table.append(row);

    }

The Results

Test on jsperf.com

You may or may not be surprised in the results. If you think about it logically, you may realise that the jQuery way is going to be naturally slower, as we are calling jQuery methods to do the work for us, so this has to result in a performance hit naturally as there is another layer to go through than simply building the HTML string(s) in a variable.

The one major thing I got for this (even tho I have always used the HTML way) was the difference in performance over the two methods. I was seeing an average of 75% difference in speed between the two when running the jsPerf test.

On a non-performance matter the HTML way is actually nicer to read (in my eyes).

Basic jQuery testing with Jasmine – Spies – Part 2

In my previous jQuery testing with Jasmine I went over the basic’s of getting everything set up and even getting a few tests running, and as these couple of post’s are about testing a jQuery plug-in rather than standard JavaScript we are using jasmine-jquery. Couple of reason I am using jasmine-jquery is mainly I am testing a jQuery plug-in, so that makes sense, and as my plug-in has click events in it we can test these events.

The examples in the post relate to the testing of my simple jQuery tabs plug-in (fluabs) which is available on GitHub with all the test’s.

Following on from the previous post, we tested the plug-in was set up and initatied on the fixture we loaded, and the default actions of the plug-in had happened. In this case only the one content area should be shown.

Now we know the plug-in can do more than that, and it should do more than that. We need to know test against the click events that the plug-in should of bound to the element to hide/show the relevant tabs.

For me I set up another describe block for testing events, happily name fluabs events:

describe('fluabs events', function() { });

In here I will test the plug-ins events for clicking on the tabs.

Test One

The first test I preform is to check if any of the tabs have a click event bound to them. As the plug-in does the event binding we can test if the event has been bound properly.

My test looks like:

  it("click tab", function() {
    var spyEvent = spyOnEvent('#tabs li a', 'click' );
    $('#tabs li a').click();
    expect( 'click' ).toHaveBeenTriggeredOn( '#tabs li a' );
    expect( spyEvent ).toHaveBeenTriggered();
  });

Ok, so let’s take a look at what this test is doing. This test is the basic example that is shown on the jasmine-jquery readme on their github page. I have modified it to work with the fluabs plug-in.

First we are assigned a spyOnEvent() function that has the element I want to perform the event on and the type of event I want to perform, to the variable spyEvent, we then trigger the event using the jQuery trigger function.
The next two lines are the test’s check a click event has happened on the element we have specified. So we expect a click to happen on the a inside the li under the #tabs element, and the second expect is to check that our spyOnEvent has been triggered

This first test is a bit open ended as all its checking is if a click event has been fired, so the plug-in could be binding the click event to the correct element but does not me the click event is working properly, we will do that next. But this is a good test to ensure we have go our event bound properly.

Test Two

The second test I preform is to check if the click event we bind in the plug-in are bound properly and do what they are supposed to do.

My test for this looks like:

it("click tab 2 - hide all tabs except tab 2, tab 2 to have class current", function() {
   var spyEvent = spyOnEvent('#tabs li a[href=#two]', 'click');
    $('#tabs li a[href=#two]').click();
    expect( 'click' ).toHaveBeenTriggeredOn( '#tabs li a[href=#two]' );
    expect( spyEvent ).toHaveBeenTriggered();
    expect( $('[data-tab="#two"]') ).toBe( ':visible' );
    expect( $('#tabs li a[href=#two]') ).toHaveClass( 'current' );
    expect( $('[data-tab="#one"]') ).not.toBe( ':visible' );
    expect( $('[data-tab="#three"]') ).not.toBe( ':visible' );
});

You will see some similarities to the first test, as we are again testing the click event, but this time we are not testing just for a click event to happen, we are testing the click event on a certain element and if it has performed the click events functions as the plug-in should be set up to do.

This means with the spyOnEvent() function will have to be more specific on the element we wish to target the click event on, so that the actual plug-in click event happens.

As this a tabs plug-in, and the way I have wrote it is, that the href part of the tabs unordered list elements is used to target the div within the .tabcontent div. The tabs list looks like:

  <ul id="tabs">
    <li><a href="#one" class="current">Tab One</a></li>
    <li><a href="#two">Tab Two</a></li>
    <li><a href="#three">Tab Three</a></li>
  </ul>

and my tabs content div looks like:

  <div class="tabcontent">
    <div class="tab" data-tab="#one">
      <p>
        This is some sample tab content in <strong>Tab One</strong>
      </p>
    </div>
    <div class="tab" data-tab="#three">
      <p>
        This is some sample tab content in <strong>Tab Three</strong>
      </p>
    </div>
    <div class="tab"data-tab="#two">
      <p>
        This is some sample tab content in <strong>Tab Two</strong>
      </p>
    </div>
  </div>

So the href part corresponds with the data-tab attribute of a div with the .tabcontent div

With that all sorted, back to the test. We have set up the click event to happen on the second tab like so :

$('#tabs li a[href=#two]').click();

Then the follow expects check that the element has been triggered on, and the spyEvent was triggered, then we check to make sure the elements on the page have changed based on what the plug-in is supposed to do.

We expected the data-tab=”#two” to be visible as we click the link with href of #two, and the plug-in adds a class of current to the a element, so we check to ensure this has happened.

Now we have checked the relevant tab is visible and the link we triggered the event on has the right class, we need to check to make sure none of the other tabcontent div’s are showing we check them to make sure they are not visible.

Basic jQuery testing with Jasmine Part 1

I have had JavaScript testing on my radar for a good few months, and in the past few months I’ve made it a big proirity to learn. So after rewriting my blog system to give me the kick up the backside, the next on my list was JavaScript Unit testing.

So for the past couple of months in my spare time I have been playing around with the JavaScript testing framework. I am going run through setting up Jasmine and jasmine-jquery and also how I tested one of my simplier plug-ins. The plug-in I am going to use in this article is a simple jQuery tab’s plug-in named fluabs. It’s available on github along with all the test’s which are not all covered in this article

What is Jasmine?

Jasmine is a behavior-driven development framework for testing JavaScript code. It does not depend on any other JavaScript frameworks. It does not require a DOM. And it has a clean, obvious syntax so that you can easily write tests.

Jasmine on Github

Why Jasmine?

I do not have a huge big pro’s and con’s of why I choose Jasmine. I was doing some research in the different JavaScript testing frameworks, and Jasmine seemed to come up alot, along with QUnit and Mocha. I tried Jasmine, then had a play with QUnint. I never actually tried Mocha as it just did not sit right with me for some reason.

After playing a little with Jasmine and QUnit, and hitting a couple of little issue’s with QUnit I just decided to stick with Jasmine, rather then fully evaluate them both and make a proper decision. So that’s how I chose Jasmine, probably not the best but I am getting on really well with Jasmine, at first the whole testing thing was really alien to me and it was Jasmine that actually made it click, or that fact I stuck at it.

On top of Jasmine, I am also using jasmine-jquery.

jasmine-jquery provides two extensions for Jasmine JavaScript Testing Framework

1, a set of custom matchers for jQuery framework

2, an API for handling HTML fixtures in your specs

Getting Started

As I am using jasmine-jquery, you need to download jasmine, aswell as jasmine-jquery. Also, as we are testing jQuery you will need a copy of jQuery. You could use a CDN, but I have downloaded it and put it in with my test’s so I have the correct version that I have used to develop the plug-in with. This would then allow us to re-run our tests when a new version of jQuery is released to check if our plug-in is compatable with it.

My folder structure for my plug-in is, which I use for all jQuery/JavaScript plug-in’s/code:

  • demo – contains a HTML file that demo’s my plug-in pulling the JS from the other folders
  • dist – contains a production ready minified version of the plug-in
  • src – this contains the unminfied development plug-in code
  • tests – this contains Jasmine/ jasmine-jquery, and my test stuff

Getting the files

  • First thing to do is download the latest standalone jasmine package from their github downloads page,
  • Extract and place somewhere. I put everything under a folder named tests within my plugin folder that I going be testing,
  • Download jasmine-jquery from their github downloads page – jasmine-jquery is a single file, this needs to be put in the lib folder that is in side the test folder we created in step 2,
  • Put a copy of the version of jQuery you need for your plug-in in the lib folder to

Adding jasmine-jquery and jquery

You now have jasmine and jasmine-jquery downloaded, you will now need to update the SpecRunner.html file to work with jasmine-jquery. It’s not too difficult just a case of adding a couple of script tags

You need to add the jasmine-jquery.js file on the line after the jasmine-html.js file like so:

<script type='text/javascript' src='lib/jasmine-jquery.js'></script>

And as we are testing jQuery you need to add jQuery to you page, which you will be familiar with. You add this on the line below jasmine-jquery.js like so:

<script type='text/javascript' src='lib/jquery.js'></script>

Now we have the testing lib’s all set up we need to add our test specs and jQuery plug-in so we can run test’s against it.

Adding plug-in and Spec

You need to add your jQuery plug-in code just like you would if you where putting it on any site, using the script tag. Rather than duplicate copies of the plug-in I reference the plug-in from the src folder as this is the development code and this code we want to test against. So I add the plug-in to the SpecRunner.html like:

<script type='text/javascript' src='../src/fluabs.js'></script>

We also need to create a Spec file that will contain our tests, I called it SpecFluabs.js and saved it in the spec folder, and referenced it in the SpecRunner.html file like:

<script type='text/javascript' src='spec/SpecFluabs.js'></script>

You will notice in the SpecRunner.html file there is the following code:

<!-- include source files here... -->
<script type='text/javascript' src='src/Player.js'></script>
<script type='text/javascript' src='src/Song.js'></script>
<!-- include spec files here... -->
<script type='text/javascript' src='spec/SpecHelper.js'></script>
<script type='text/javascript' src='spec/PlayerSpec.js'></script>

This is the default spec code and JavaScript code that is tested against, I remove the script tags and replace them with reference to my JavaScript and Spec files.

Testing the plug-in

As I had already written the plug-in, I’ve just added tests to prove it’s working. We could then use the testing framework set up to do test-driven development if I or someone else would like to contribute to the plug-in.

Now we got the test folder all set up we can start writing some test’s to check the plug-in does what it’s supposed to do.

The basics of Jasmine. Jasmine uses’ Suites to describe your tests, Specs which contain one or more expections, Expections which take a value, which your matcher is responsilbe for checking if your expection is true or false.

For complete documentation see the jasmine documentation

Tests

Right we have everything set up, lets write some tests. Ah one more thing, as we are testing a jQuery plugin we need to load the HTML required for the plug-in and bind the plug-in to it to simulate it being in the DOM. With jasmine-jquery you get the ability to have HTML fixtures, which is way you can load HTML content that is needed for your tests.

For this plug-in we need a fixture that contains the sample HTML needed for the plug-in. I put my fixtures in a folder named fixtures within the tests/spec/. You need to update jasmine-jquery.js to reflect where you have put your fixture folder, this is on line 76 ofjasmine-jquery.js

So we create a file named fluabs.html inside of the fixtures folder and add the HTML needed for our plug-in.

We now need to make this fixture avaiable to our test’s, which you do using loadFixtures() in your test spec.

For testing this plug-in we want to reset the state of our test code and plug-in, so that it’s as if the page has just loaded and nothing has happened. We do this using a beforeEach(). So we want to load our fixture inside of the beforeEach() function and initaite the plugin. We do this like:

var fixture;
beforeEach(function () {
  loadFixtures('fluabs.html');
  fixture = $('#tabs');
  fixture.fluabs();

});

We have defined a variable name fixture which we can use later on to test againt in our Specs. We then use the beforeEach() to load our fixture and then to initaite our plug-in. As we have told the plug-in and HTML to load beforeEach(), it will load before each spec in the describe, so we want to reset the code by using afterEach(). So we set our Suite up and theafterEach() function:

  afterEach(function () {
    $('#tabs').remove();
  });

Now we have the plug-in and the HTML needed for our plug-in getting loaded beforeEach test and our plugin is removed after each, we can start writing some tests.

We use the describe() function to set up a suite which will contain multiple specs and a nested suite with more specs.

describe('fluabs', function() {
});

Now we need to add our first spec, so the first test we need to do is to check if the plug-in has been defined and we do this like:

it('to be defined', function() {
   expect( fixture ).toBeDefined();
});

Open SpecRunner.html in your browser (use FireFox or Safari, or read the documentation on how to use Chrome), and this should pass, if not we have an issue!

Our second spec would be to check that the first content area is shown and the others are not, as we are using the plug-in with default option’s we know this is what should happen so we set our spec, expections and matchers to check all this:

it('tab one to be shown and others to be hidden', function() {
    expect( $('[data-tab='#one']') ).toBe( ':visible' );
    expect( $('[data-tab='#two']') ).not.toBe( ':visible' );
    expect( $('[data-tab='#three']') ).not.toBe( ':visible' );
  });

As we are using jasmine-jquery and jQuery we can use jQuery selectors in our expect.

Refresh your SpecRunner.html (sometimes you may need to clear your cache) and see all green.

So we have some basic test’s set up, for our plug-in, in another article I will go into more depth on testing with spies to test click events and make sure everything works.

jQuery Performance : attributes

If you use jQuery you have more than likely needed to do something with an elements attribute(s), whether that be get the value/data from it or set the attribute of an input or add a data attribute for future reference.

As you are probably aware there are multiple ways in jQuery to get different attribute values. These methods are:

.attr()

.prop()

.data()

.val()

If you are not sure on what these four methods do here is a quick overview, but I do recommend going to ready the jQuery Documentation.

.attr() – Can be used to either get the value of a specified attribute or set the value.

$(‘input’).attr(‘type’)would get the value of the type attribute to the input.

$(‘input’).attr(‘type’,’text’)would set the type attribute to text for the input element(s)

.prop() – is used in the same way as .attr() you can either get the value or set it. This was introduced in jQuery v1.6

.data() – is used to store or access custom data from an element, so you can used it to fetch an HTML5 data attribute

$(‘input’).data(‘validation’)would fetch the data-validation attribute value

.val() – Used to the current value of the element(s), or to set the value of the element

$(‘input’).val()Would get me the contents of the value attribute

$(‘input’).val(‘Matthew’)Would set the input value to Matthew

Tests

So with these different ways of getting different attributes and setting them, which one(s) should we be using?

I know I’ve been a sucker for using the .attr() method for most things, and the the .val()method when ever I’ve needed to get or set the value. But I am a performance nerd and like to question myself/ or others on the way they are writing code.

I have put together a set of tests to show some different scenarios of using this methods to see what’s the quickest way, and when you should be using a certain method for a certain tasks.

All tests have been done with the latest jQuery.

Getting element attribute: .attr() vs .prop()

We are testing which method is quickest between .attr() and .prop() to get a standard HTML attribute of an input

Tests

HTML – <input type=’text’ name=’name’ value=’Joe Bloggs’ data-validation=’min: 3′ />

attr – $(‘#test’).attr(‘type’);

prop – $(‘#test’).prop(‘type’);

Results

So as you will see from the graph below the results for this test are very close making it a bit of a tie. There was no clear winner for speed, and one method was not always fastest.

getting_attribute_attr_prop

Test on jsperf

Setting an input value: .attr() vs .prop() vs .val()

Test to see which method is the fastest for setting the value of an input, using .attr(), .prop()and .val()

Tests

HTML – <input type=’text’ id=’foo’ />

attr – $(‘#foo’).attr(‘value’, ‘Test’);

prop – $(‘#foo’).prop(‘value’, ‘Test’);

val  – $(‘#foo’).val(‘Test’);

Results

The results for this are interesting as the clear winner is the .prop() method, but there is also a little difference between firefox and the rest of the browsers, while Firefox is much slower for all three tests, but all three test are very close in performance wise.
The winner is .prop() for this test.

setting_input_value

Test on jsperf

Getting data attribute: .attr() vs .data()

Update – prop() is not always the go to method for getting attributues, it can not get data-xdata and a few others, but I’ll write a post about this.

Test to see which method is the quickest to get the value of a data attribute.

Tests

HTML – <input type=’text’ name=’name’ value=’Joe Bloggs’ data-validation=’min: 3′ />

attr – $(‘#test’).attr(‘data-validation’);

data – $(‘#test’).data(‘validation’);

Results

The one thing I found interesting about this test was I thought that the .data() method would come out on top, as the method name suggest’s that we should use this method to get the data, but turns out this is the slowest. You should either use .attr(). The difference is speed is very slight and varies between browsers.

Test on jsperf

Setting a checkbox: .attr() vs .prop()

Test to get the quickest way to set the checked attribute on a checkbox. This was actually my first test which started off this blog post, but I wanted to cover some basics first to make sure I was not barking up the wrong tree.

I ran two test for each method as you can set the checkbox to checked using the HTML way of checked=’checked’ or by passing true. I write my jQuery using checked over the true way as I have seen some browser issues with the true way.
But I wanted to test the true vs checked way to see if there was any major difference in performance.

Tests

HTML – <input type=’checkbox’ id=’foo’ />

attr – $(‘#foo’).attr(‘checked’, true);

prop – $(‘#foo’).prop(‘checked’, true);

attr checked – $(‘#foo’).attr(‘checked’, ‘checked’);

Prop Check – $(‘#foo’).prop(‘checked’, ‘checked’);

Results

The .prop() method wins hands down on this test, and I was amazed at how much by. Over 40% quicker in some cases which is a lot if you are do a lot of form manipulation with jQuery.
Another surprise I got with the results from this test is the difference in speed between the major browsers. I was surprised by the speed difference of Chrome to Safari, and also the speed of Firefox against the others.

jquery_performance_setting_attributes

Test on jsperf

Conclusion

With running these tests, I learnt that not to rely on jQuery methods that you think are doing the job properly for you. The fastest way to manipulate element’s attributes is the .prop()method.

jQuery Performance: for vs $.each

So you are using jQuery, pretty much everyone is using it (no stats to back this up, but it’s used a lot), and it’s full of awesome stuff. With jQuery, like many other languages it’s also possible to write code that can get you the end result in multiple ways. But is it the most efficient way?

You may think that because you are using jQuery you need to use all jQuery’s function’s, this is wrong. jQuery is just a wrapper around JavaScript functions making them easier to understand and use for the average user. While for 9 out of 10 scenario’s it’s great, the average user may be using jQuery to spice up their website a little to give it some wow factor. But should you settle for average? I say no, but depending on how far you wish to go with jQuery/ JavaScript your answer will differ to mine.

Back a year or so ago, I would of been the one who was saying it’s fine just use the jQuery functions they are nice and easy, it can not be that bad. But since working on some big web apps with hundreds of thousands of users actively using the apps on a daily basis and spending a large chuck of their time doing meaningful work in them. I have started taking a really hard look into the way I am writing jQuery and the performance of the jQuery functions I am using.

A while back I was implementing a bit of custom functionality into a web app, where users could filter rows in a table using an input box, sort of like a live search. The more they type the more rows disappeared. Sounds straight forward enough, but the table is up over a hundred rows and has around 5 or 6 columns.
The code was first implemented using the jQuery $.each function to loop over the rows and determine if the value entered in the search box matched something in the row, if it did cool, if not hide the row. Again sounds straight forward. All seemed to work with the code for a little while, but over time, and when more rows where added and the complexity of the search grew the speed dropped very quickly and at some points there was lots of browser lag and sometimes the browser would crash.

So, I went in search of a fix. I rewrote the code a few times to see if I could make it neater and learner, but it all ended up at pointing to the $.each that was in there. So I went digging into the jQuery source to find that the $.each function is a nice wrapper for a native JavaScript loop.

I re-wrote the $.each to use a for loop and the code works perfect. This lead me onto to do some research into it.

So a quick search reveals a jsperf.com test on a for loop vs a jQuery $.each loop. And as you’ll see from the test data the native JavaScript for loop is nearly twice as fast as a jQuery $.each.

While for the most part the developer who is doing stuff for their personal site or a site for the local business down the road, would not hit the issues I was having with my code in this scenario I found it intriguing at how much faster the native for loop was.

Think of it this way, as the native loop is nearly twice as fast that means I could do the same loop nearly twice, by the time jQuery would have done it once, making not only the site faster, but taking strain away from the browser and giving the user a faster and more tolerable user experience.

The more I write with jQuery the more I am looking into the source to see what it is wrapping for me, as you must not forget jQuery is just a nice library for JavaScript, while it does help with a lot of cross platform/browser issues there is also a lot you can learn performance wise by going into the source and actually seeing what it is doing.

Note I am not suggesting that jQuery do not pay attention to performance far from it, John Resig and the jQuery core developers put a lot of effort into jQuery and I don’t mean to take anything away for that.

But sometimes you are simply not able to match the native speed using a wrapper. I working in jQuery on a near daily basis and love what they have done.