Jquery Performance Tuning

After searching and digging a lot of artciles about improving jquery performance in web apps, I decided to make a list of best common performance tips and bect practices. We’ll also reveal some of JQuery’s hidden feature and how we can use them for performance tuning.

Lets divide this post into 4 main categoris.

  • Selector Performace
  • DOM Manipulation
  • Events
  • Digging into JQuery Secrets
  • General and All-Time performance tricks

Selector Performace

Know your selectors

You should be careful about using jquery selectors because all selectors are nor created equally. With benchmarks, we can see:

  $('#id, element'); // Id and Element selectors are the fastest
  // the reason is because it maps to a native JavaScript methods
  $('.class_name'); // Slower class selectors
  $(':hidden, [attribute=value]'); // Pseudo and Attribute selectors are the slowest

Optimize selectors for Sizzle’s ‘right to left’ model

JQuery as of now uses the Sizzle Javascript Selector Library which works a bit differently from the selector engine used in the past versions. Namely it uses a ‘right to left’ model rather than a ‘left to right’. Make sure that your right-most selector is really specific and any selectors on the left are more broad:

  var linkContacts = $('.contact-links div.side-wrapper'); // Good
  var linkContacts = $('a.contact-links .side-wrapper'); // Bad

Keep it Simple!

Avoid overly complex selectors. Unless you have an incredibly complex HTML document, it’s rare you’ll need any more than two or three qualifiers.

  $("body #page:first-child article.main p#intro em"); // Bad
  $("p#intro em"); // Good

Class selectors and Context

Always try to scope your selectors with id or element.

  $('.active').show(); // bad
  $('#header .active').show(); // better
  $('.active', '#header').show(); // better
  $('#header').find('.active').show(); // fastest
  // .find() is faster because it directly uses native javascript methods to search inside the passsed context under the hood
  $('button.active'); // fastest
  // grabs all matches tags FIRST, then iterates through them to find matching classes

DOM Manipulation

Cache and Chains to Avoid Reselection

Interacting with the DOM as little as possible will drastically speed up your applications.

  // Bad
  $('#sidebar .promo').hide();
  $('#sidebar .newPromo').show();
  $('#sidebar').after(somethingcool);

  // Good
  var sb = $('#sidebar');
  sb.find('.promo').hide();
  sb.find('.newPromo').show();
  sb.after(somethingcool);

  // Bad
  $("p").css("color", "blue");
  $("p").css("font-size", "1.2em");
  $("p").text("Text changed!");

  // Good
  $("p").css({ "color": "blue", "font-size": "1.2em"}).text("Text changed!");

Wrap everything in a single element when doing any kind of DOM insertion

DOM manipulation is very slow. Try to modify your HTML structure as little as possible.

  var menu = '<ul id="menu">';
  for (var i = 1; i < 100; i++) {
      menu += '<li>' + i + '</li>';
  }
  menu += '</ul>';
  $('#header').prepend(menu);

  // Instead of doing:

  $('#header').prepend('<ul id="menu"></ul>');
  for (var i = 1; i < 100; i++) {
      $('#menu').append('<li>' + i + '</li>');
  }

Events

Leverage Event Delegation

Event listeners cost memory. In complex websites and apps it’s not uncommon to have a lot of event listeners floating around, and thankfully jQuery provides some really easy methods for handling event listeners efficiently through delegation.

When you have a lot of elements in a container and you want to assign an event to all of them – use delegation to handle it. Delegation provides you with the ability to bind only one event to a parent element and then check on what child the event acted (target). It’s very handy when you have a big table with a lot of data and you want to set events to the TDs. Grab the table, set the delegation event for all the TDs:


  $("table").delegate("td", "hover", function(){

    $(this).toggleClass("hover");

  });

Digging into JQuery Secrets

Element Creation

The following snippet is enough what I mean:


  var myDiv = jQuery('<div/>', {
    id: 'my-new-element',
    class: 'foo',
    css: {
      color: 'red',
      backgrondColor: '#FFF',
      border: '1px solid #CCC'
    },
    click: function() {
      alert('Clicked!');
    },
    html: jQuery('<a/>', {
      href: '#',
      click: function() {
        // do something
        return false;
      }
    })
  });

Writing own selectors

If you have selectors that you use often in your script – extend jQuery object $.expr[’:’] and write your own selector. In the following example We create a selector above_the_fold that returns a set of elements that are not visible:


  $.extend($.expr[':'], {
    above_the_fold: function(el) {
      return $(el).offset().top < $(window).scrollTop() + $(window).height();
    }
  });
  var nonVisibleElements = $('div:above_the_fold'); // Select the elements

CSS Hooks

The CSS hooks API was introduced to give developers the ability to get and set particular CSS values. Using it, you can hide browser specific implementations and expose a unified interface for accessing particular properties.


  $.cssHooks['borderRadius'] = {
    get: function(elem, computed, extra){
      // Depending on the browser, read the value of
      // -moz-border-radius, -webkit-border-radius or border-radius
    },
    set: function(elem, value){
      // Set the appropriate CSS3 property
    }
  };

  // Use it without worrying which property the browser actually understands:
  $('#rect').css('borderRadius',5);

What is even better, is that people have already built a rich library of supported CSS hooks that you can use for free in your next project.

General And All time tricks

Use HTML5

You may wonder how jquery performance and HTML5 are related but the new HTML 5 standard comes with new tags and a lighter DOM structure in mind. Lighter DOM structure and different tags diferent purpose for means less elements to traverse for jQuery.

DOM isn’t your database

Traversing DOM to retrieve information stored in .text(), .html() is not optimal approach. Use html5 data to attach any kind of information in DOM. With the recent updates to the jQuery data() method, HTML5 data attributes are pulled automatically and are available as entries.

  <div id="d1" data-role="page" data-page_hash="H4jk8s00">
  </div>

  $("#d1").data("role"); //page
  $("#d1").data("page_hash"); //H4jk8s00

Append style tag when styling 15 or more elements

When styling a few elements it is best to simply use jQuery’s css() method, however when styling 15 or more elements it is more efficient to append a style tag to the DOM instead of applying css to each items.

  $('<style type="text/css"> div.activated { color: red; } </style>').appendTo('head');

Always use the latest version

JQuery is always in constant development and improvement. The latest version always contains more bug fixes and performance improvements so it is always wise to keep upto date with the latest versions.

Combine jQuery with raw Javascript where needed

  $('#someAnchor').click(function() {
    alert( $(this).attr('id') );
  });

  $('#someAnchor').click(function() {
    alert( this.id );
  });

Load the framework from Google Code

I urge everyone to use the Google AJAX Libraries content delivery network to serve jQuery to users directly from Google’s network of datacenters. Doing so has several advantages over hosting jQuery on your server(s): decreased latency, increased parallelism, and better caching.

The only disadvantage is that if the connection to the CDN were to fail, our site would be left with no jQuery library which could be a big deal if we run a jQuery intensive website. If it happens then there should be some mechanism to fetch the library from other source or from our own locally hosted location. Fortunately, you can easily reference a backup. You can have a copy of jQuery on your server, and use a little bit of JavaScript to load it only if the Google one doesn’t load for some reason. This little snippet, found in HTML5 Boilerplate, will do just that:

  <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
  <script>window.jQuery || document.write('<script src="js/libs/jquery-1.9.0.min.js"><\/script>')</script>
Read More...

Feature flippers with rollout

Rollout gem comes handy when we need deploy a beta feature, may be to a selected group of users or some percentage of uses so that few users can try it out before it goes massive.

So lets rollout.

We’ll be using redis as rollout’s backend.

To setup, jusst add gem 'rollout' to Gemfile and run bundle install.

Now, we need to create a rollout setup file inside initializer.

Let’s name it rollout_init.rb which looks like this:


  $redis = Redis.new
  $rollout = Rollout.new($redis)
  $rollout.define_group(:admin) do |user|
    user.admin?
  end

Documentation suggests to use a global variables. So we create one with a new redis instance. Then, we create rollout instance passsing that redis instance. We can configure rollout in many ways, here we are defining an admin group by passing a block and checking whether the user belongs to that group or not. Complete documentation can be found here.

Next, we can now use handy rollout method like for example let’s say we need to activate chat feature for admin group only.


  if $rollout.active? :chat, current_user

    ....

  end

The $rollout.active? method accepts the name of the feature and the user and returns true or false.

This method is accessible in views as well as in controllers. That’s not all, if you restart your server now and look at the app, you may find out that the feature is unavailable to admin groups also, it is because by default the feature is deactivated to all groups or users. We can make a rake task or an interface for activating the feature to subset of users. Activating code looks like this:


  $rollout.activate_group(:chat, :admin)

This will activate the feature ( chat in our case ) for admin group.

Also we can activate the feature to all users or specific user or to some percentage.


  $rollout.activate_group( :chat, :all ) #activate to all, there is all group already by default

  $rollout.activate_user( :chat, User.find_by_email("admin@myapp.com") ) #activate to specific user

  $rollout.activate_percantage( :chat, 50 ) #activate to 50% of users

Each of these methods have deactivate version for deactivating the feature. You can also just call $rollout.deactivate_all(:chat) to deactivate the feature to all at once.

Read More...

MySql commands

This is a short-list of handy MySQL commands that I have to use time and time again, in my development machine as well as in servers and for importing and exporting databases.

Login to mysql console (from unix shell)

  $ mysql -u user -p
  # if host name is required
  $ mysql -h hostname -u user -p

Create a new database

  mysql> create database databasename;

List all databases

  mysql> show databases;

Switch to a database

  mysql> use database_name;

List tables

  mysql> show tables;

See database’s field formats.

   mysql> describe table_name;

Drop a db.

  mysql> drop database database_name;

Delete a table.

  mysql> drop table table_name;

Show all data in a table.

  mysql> SELECT * FROM table_name;

Returns the columns and column information pertaining to the designated table.

  mysql> show columns from table_name;

Set a root password if there is on root password.

  $ mysqladmin -u root password newpassword

Update a root password.

  $ mysqladmin -u root -p oldpassword newpassword

Recover a MySQL root password. Stop the MySQL server process. Start again with no grant tables. Login to MySQL as root. Set new password. Exit MySQL and restart MySQL server.

  $ /etc/init.d/mysql stop
  $ mysqld_safe --skip-grant-tables &
  $ mysql -u root
  mysql> use mysql;
  mysql> update user set password=PASSWORD("newrootpassword") where User='root';
  mysql> flush privileges;
  mysql> quit
  $ /etc/init.d/mysql stop
  $ /etc/init.d/mysql start

Export a database for backup.

  $ mysqldump -u user -p database_name > file.sql

Import a database

  $ mysql -p -u username database_name < file.sql

Dump all databases

  $ mysqldump -u root -password --opt > alldatabases.sql
Read More...

Javascript Private and Public methods

Objects and Classes

JavaScript is a prototype-based language which contains no class statement, such as is found in other object oriented languages. This is sometimes confusing for programmers accustomed to languages with a class statement. Instead, JavaScript uses functions as classes. Defining a class is as easy as defining a function. In the example below we define a new class called Person.

  function Person() { }

To create a new instance of an object new operator.

  my_person = new Person();
Read More...

Javascript Static and Instance methods

Custom JavaScript objects can have instance methods (function that are associated with a particular JavaScript object), but like other Object-Oriented languages, they can also have static methods, that is functions that are associated with the JavaScript class that created an object, as opposed to the object itself. This is useful in cases where a function (a.k.a. a method) will not be different in different object instances.

Read More...