Deep Profiling jQuery Apps


This evening I was playing around with the idea of profiling jQuery applications – trying to find a convenient way to completely analyze all the code that is being executed in your application.

I’ve come up with a plugin that you can inject into a jQuery site that you own and see how the performance breaks down method-by-method.

Here’s how you can try this plugin on your own site:

Step 1: Copy site HTML, add base href, add plugin.

For example, Github.com uses jQuery for a few basic effects and pieces of interaction (they use considerably more on pages beyond the homepage).

I took a copy of their page, added a <base href> to the top and injected the profiling plugin giving a resulting test page.

Before:

  1. <head>
  2.     <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
  3.     ...
  4.     <script src="/javascripts/bundle.js"></script>
  5.     ...
  6.   </head>

After:

  1. <head>
  2.     <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
  3.     <base href="http://github.com/"/>
  4.     ...
  5.     <script src="/javascripts/bundle.js"></script>
  6.     <script src="http://dev.jquery.com/~john/plugins/profile/jquery-profile.js"></script>
  7.     ...
  8.   </head>

Step 2: Use the site normally.

Use the site as you normally would. Load it up, click around – perform normal interactions. In the case of the Github.com page I let it load, scrolled down, and clicked on one of the demo images – which caused an overlay to appear. I then closed the X on the overlay and let it hide.

Step 3: View data.

In your console type jQuery.displayProfile(); and scroll down to the bottom of the page. You should see something like the following:

and here’s a sample data dump:

Event: ready (165ms)
% (ms) Method in out
0.0% 0 jQuery(#document) 1
0.0% 0   .bind(“ready”, function()) 1 1
3.6% 6 jQuery(“a[hotkey]“)
0.0% 0   .each(function())
0.0% 0 jQuery(#document) 1
0.0% 0   .bind(“keydown.hotkey”, function()) 1 1
0.0% 0 jQuery(“#triangle”)
0.0% 0 jQuery(“body”) 1
1.2% 2   .append(“<div id=”triangle” style=”position: absolute; display: none;”> </div>”) 1 1
0.6% 1 jQuery(“#repo_menu .active”)
3.6% 6 jQuery(“.jshide”)
0.0% 0   .hide()
1.2% 2 jQuery(“.toggle_link”)
0.0% 0   .click(function())
0.6% 1 jQuery(“#beta :text”)
0.0% 0   .focus(function())
0.6% 1 jQuery(“#beta form”)
0.0% 0   .ajaxForm(function())
1.2% 2 jQuery(“.hide_alert”)
0.0% 0   .click(function())
0.0% 0 jQuery(“#login_field”)
0.0% 0   .focus()
0.0% 0 jQuery(“#versions_select”)
0.0% 0   .change(function())
1.2% 2 jQuery(“a[rel*=facebox]“) 3
17.6% 29   .facebox() 3 3

Event: load (1ms)

% (ms) Method in out

Event: click (29ms)

% (ms) Method in out
6.9% 2 jQuery(“#facebox .loading”)
3.4% 1 jQuery(“facebox_overlay”)
3.4% 1 jQuery(“body”) 1
6.9% 2   .append(“<div id=”facebox_overlay” class=”facebox_hide”></div>”) 1 1
0.0% 0 jQuery(“#facebox_overlay”) 1
6.9% 2   .hide() 1 1
3.4% 1   .addClass(“facebox_overlayBG”) 1 1
0.0% 0   .css(“opacity”, 0) 1 1
3.4% 1   .click(function()) 1 1
6.9% 2   .fadeIn(200) 1 1
3.4% 1 jQuery(“#facebox .content”) 1
3.4% 1   .empty() 1 1
3.4% 1 jQuery(“#facebox .body”) 1
0.0% 0   .children() 1 2
10.3% 3   .hide() 2 2
0.0% 0   .end() 2 1
6.9% 2   .append(“<div class=”loading”><img src=”/facebox/loading.gif”/></div>”) 1 1
0.0% 0 jQuery(“#facebox”) 1
0.0% 0 jQuery({…}) 1
3.4% 1   .width() 1
0.0% 0   .css({…}) 1 1
6.9% 2   .show() 1 1
0.0% 0 jQuery(#document) 1
0.0% 0   .bind(“keydown.facebox”, function()) 1 1
0.0% 0 jQuery(#document) 1
3.4% 1   .trigger(“loading.facebox”) 1 1

Event: beforeReveal.facebox (1ms)

% (ms) Method in out

Event: click (6ms)

% (ms) Method in out
16.7% 1 jQuery(#document) 1
66.7% 4   .trigger(“close.facebox”) 1 1

Event: close.facebox (3ms)

% (ms) Method in out

This quick table of data should be able to provide you with some interesting information about what’s happening in your code. The result is still incredibly basic (really only providing the most basic level of jQuery method introspection) but it definitely shows some merit.

If you wish to create a different view for the data you can access the raw data structure by running jQuery.getProfile();.

The next stage of development for this plugin would be to reveal which methods are running inside other jQuery methods – in addition to monitoring other aspects of the application (such as timers, Ajax callbacks, etc.). I’m pleased with even this most-basic result – it gives me the ability to quickly, and easily, learn much more about a jQuery-using application.

Posted: June 16th, 2008


If you particularly enjoy my work, I appreciate donations given with Gittip.

29 Comments (Show Comments)



Comments are closed.
Comments are automatically turned off two weeks after the original post. If you have a question concerning the content of this post, please feel free to contact me.


Secrets of the JavaScript Ninja

Secrets of the JS Ninja

Secret techniques of top JavaScript programmers. Published by Manning.

Ukiyo-e Database and Search

Ukiyo-e.org

Japanese woodblock print database and search engine.


John Resig Twitter Updates

@jeresig

Infrequent, short, updates and links.