solnic on blog web development, ruby, javascript and other crazy things

15Jan/098

Client-side rendering with Prototype

Web applications are getting more and more complex. The user interface of a modern web application can be as rich as its desktop equivalent. If we use JavaScript/HTML/CSS trio to build this UI then we definitely want to use AJAX. A typical approach is to use AJAX to update parts of our page using an HTML response, everyone knows that, right? Does this approach allow us to create a responsive, fast and flexible UI? The answer is no.

Here are 4 main downsides of using AJAX requests to load UI parts:

  • You increase the server load – yes, you make an AJAX request only because you need a piece of HTML code that you want to insert to an already rendered page. That was cool a few years ago when AJAX was such a great innovation. Nowadays it should be considered as a less efficient solution.
  • You complicate the server-side code – because you need parts of your page to be returned by the server you, obviously, need to handle that by writing more server-side code. You end up having many actions in your controllers that return different fragments of HTML. I know, you think it’s normal, everyone does that.
  • You loose a lot of control over the UI – you use DHTML techniques to deal with the UI and in the same time you need the server to get parts of that UI. This leads to a code duplication and in many cases ends up with a big mess.
  • A user will have to wait until a request is done – that just sucks, that poor guy has to wait because you went back to the server for a little piece of HTML. How you are going to implement a responsive UI this way? “Your servers are fast”. Of course they are, but what if user’s ISP sucks? What if the user is downloading something and 99% of his bandwidth is gone?

Rendering HTML on the client-side is ridiculously simple. Consider the following example. Let’s say we have a page with a list of some people, the list is just a simple HTML table. It could look like this:

<table>
  <thead>
    <tr>
      <th>First Name</th>
      <th>Last Name</th>
      <th>E-Mail</th>
    </tr>
  </thead>
  <tbody id="people">
    <!-- here go people -->
  <tbody>
  <tfoot>
    <tr colspan="4">
      <td>
        <a id="previous" href="#">Previous</a> 
        <a id="next" href="#">Next</a>
      </td>
    </tr>
  </tfoot>
</table>

As you can see the tbody element is empty, we will load its content after the entire page is loaded. Instead of a bunch of “tr” elements the server should return a nice JSON data which could look like this:

var people = [
 { id : 1, first_name : 'John', last_name : 'Doe', email : 'john.doe@somewhere.com' },
 { id : 2, first_name : 'Jane', last_name : 'Doe', email : 'jane.doe@anywhere.com' },
 { id : 3, first_name : 'Third', last_name : 'Guy', email : 'third.guy@nowhere.com' }
];

To render these data we obviously need a template. Prototype gives us a handy class called Template which is perfect for our needs. To create a template and render the list of people we need a few lines of JavaScript:

var personRowTemplate = new Template(
  '<tr id="person_#{id}"><td>#{first_name}</td><td>#{last_name}</td><td>#{email}</td></tr>');
 
var peopleRows = '';
 
people.each(function(person) { 
  peopleRows += personRowTemplate.evaluate(person); 
});
 
$('people').update(peopleRows);

That’s pretty much it. It doesn’t look spectacular, huh? Now just think about the benefits of this approach:

  • You have the data in JSON format, you can use them to render things like an edit form without going back to the server, thus user experience will be better
  • You can be focused on building a nice JSON API for accessing data instead of implementing actions that return small pieces of HTML
  • Your client-side code is cleaner and more consistent

Sounds like a good deal, doesn’t it? :)

31Dec/080

My brand new blog and WordPress

Because of the rails & merb merge thing I have decided to hold off on working on Utype until the merge is finished. Unfortunately I don’t have enough time to finish Utype using Merb 1.x just to port it to Merb 2.x and then to Rails 3.0. As a side effect of my decision I have migrated my Utype-based blog to Wordpress, which is a scary PHP-based piece of software with one important advantage – it does the job right. It’s not as cool as I thought but I will be using it anyway since it’s probably the best CMS out there (at the moment…:)).

The fact that I’m using Wordpress now and I don’t spend hours working on my own CMS system means that finally I will have time to write something here more frequently.

…and BTW - Happy New Year Everyone :)

Filed under: Blog No Comments
3Feb/08Off

jQuery vs Prototype – part II

Recently, new versions of jQuery and Prototype have been released – it’s a perfect moment for a part number 2. On the official Prototype blog we can read that the general performance of CSS selectors is now improved, unfortunately only for Safari 3, but Element#up/#down/#next/#previous should now be faster on all browsers, it’s a good news as they were really slow. On the other hand we have jQuery official announcement with information that jQuery is now 300% faster – we’ll see!

This time I made a step forward and decided to use a custom JavaScript-based testing environment instead of running tests using Firebug profiler. The obvious advantage is that I was able to run all the tests on 4 different browsers. New test cases aren’t much different then in the first part, let’s say it’s a modification of the previous ones with some extra operations and a little more complex HTML structure.

Test environment setup

Libraries:

  • jQuery 1.2.2
  • Prototype 1.6.0.2

All the tests were run on the following browsers:

  • Firefox 2.0.0.11
  • Konqueror 4.00.00
  • Opera 9.50_beta1
  • Internet Explorer 7 (*but using Windows on VirtualBox!*)

A tiny piece of JavaScript code is responsible for running the tests, each operation is called only once inside a try-catch block, so the essential part looks like this:

    try {
      var start = new Date;
      test();
      var end = new Date - start;
      this.writeResults(test, end);
    } catch(e) {
      test.resultCell.innerHTML = '<div style="color: red">Exception caught: '+e.message+'</div>';
    }

There is a 3 seconds break between each test run, results are automatically inserted into the results table. If you want, you can check it out on your own, just go right here and hit the ‘run tests!’ button.

The results

I’m happy to see that all tests pass on the latest Konqueror, previous version from KDE3 fails on some Prototype tests. I don’t own Mac, so you won’t see Safari results here, although I’ve run the tests on my friend’s MacBook with very similar hardware as my laptop has (Intel Core Duo 2ghz + 2 gigs of RAM), and it was faster even then Konqueror (no, it doesn’t mean his MacBook is faster then my laptop!!!! ;) ).

I’ve run everything 3 times, here are average results in ms:










# Library Test Firefox Konqueror IE7 Opera
1 jQuery
$('td.counter').addClass('marked')
96.6 32.3 70 37
Prototype
$$('td.counter').each(function(el){ 
  el.addClassName('marked') 
})
108.3 49.6 858 75.7
2 jQuery
$('td.counter span.special').removeClass('special')
62 23.6 46.6 25.6
Prototype
$$('td.counter span.special').each(function(el) { 
  el.removeClassName('special') 
})
28 23.7 167 24.7
3 jQuery
$('td.content span.odd').css('color', 'red')
124.7 40.3 63.7 38.3
Prototype
$$('td.content span.odd').each(function(el) { 
  el.setStyle('color: red') 
})
55.7 31 297 33.7
4 jQuery
$('td.content span.even').before(
  '<h3 style="display: none">text</h3>'
)</code
382.7 177.3 373.7 205.3
Prototype
$$('td.content span.even').each(function(el) { 
  el.insert({ 
    before:'<h3 style="display:none">text</h3>' 
  }) 
})
359 90.7 527 138.7
5 jQuery
$('td.content h3').show()
178.7 227.7 83.3 1161.7
Prototype
$$('td.content h3').each(Element.show)
38 21 250.7 19
6 jQuery
$('div.special').hide()
90 81.3 33.7 375.3
Prototype
$$('div.special').each(Element.hide)
18 7 73.3 12
7 jQuery
$('div.special, td.content .odd').toggle()
637.7 431.7 517 1360.3
Prototype
$$('div.special, td.content .odd').each(Element.toggle)
71 43.7 106.7 43
8 jQuery
$('span.odd').remove()
132.7 59.3 123.3 66.7
Prototype
$$('span.odd').each(Element.remove)
29 11.7 36.7 19.3
9 jQuery
$('#data p.lost:first').html('gotcha!')
5 1.7 10 3.3
Prototype
$('data').down('p.lost').update('gotcha!')
11.7 2 10 7.3

Conclusion #2

Prototype was at least 2 times faster then jQuery in 15 cases, and jQuery was faster then Prototype in 8 cases. What library should I choose? In my case I will stick with Prototype, because it offers the same functionality as jQuery does + more and it's faster. jQuery is probably better for projects where there's a need for some fancy UI effects and that's it, but it's just an assumption, correct me if I'm wrong...

11Nov/07Off

jQuery vs Prototype – part I

Prototype 1.6.0 was released to the public 4 days ago, at first I decided to check its performance and new features in comparison to the previous version, but being interested in other JavaScript libraries, I’ve changed my mind. Lets see how you can accomplish same tasks with the latest Prototype and jQuery libraries and simply see which one is faster. In this part I’m going to show the results of running single operations, in next part(s) I will prepare a sample website and write more complex test cases and, again, check how fast jQuery and Prototype can be (or how slow…).

Test environment setup

The following software was used:

  • Prototype 1.6.0
  • jQuery 1.2.1
  • Firefox 2.0.0.9
  • Firebug 1.05
  • Webdeveloper 1.1.4

Test page contains only one table with 500 rows, it’s generated using the following RHTML template:

<table>
<% (1..500).each do |i| %>
  <tr>
    <td class="first">
      <div><%= i %></div>
    </td>
    <td class="second">
      <div><%= "hello from #{i}" %></div>
    </td>
  </tr>
<% end %>
</table>

Running the tests

Each operation was executed using Firebug’s console with Profiler turned on and repeated 3 times, between each execution the page was reloaded. Cache in Firefox was disabled using Webdeveloper plugin. Here are the results of 7 test operations showing average times and number of method calls in each operation:

1. Adding ‘marked’ CSS class to every cell having ‘first’ CSS class:

Library Operation Time (ms) Method Calls
jQuery
$('td.first').addClass('marked')
102.495 3032
Prototype #1
$$('td.first').each(function(cell) { cell.addClassName('marked') });
117.162 7056
Prototype #2
$$('td.first').invoke('addClassName', 'marked');
129.972 8062

Comment: no practical difference, although jQuery is a little faster.

2. Removing CSS class from every table cell having “second” CSS class:

Library Operation Time (ms) Method Calls
jQuery
$('td.second').removeClass('second')
109.855 3032
Prototype #1
$$('td.second').each(function(cell) { cell.removeClassName('second') });
87.445 4551
Prototype #2
$$('td.second').invoke('removeClassName', 'second');
100.64 5557

Comment: No big difference, especially when comparing Prototype #2 option with jQuery.

3. Setting ‘color’ CSS property in every div element which is inside a cell having ’second’ CSS class:

Library Operation Time (ms) Method Calls
jQuery
$('td.second div').css('color', 'red')
173.906 3536
Prototype #1
$$('td.second div').each(function(el) { el.setStyle({ color : 'red' }) });
87.585 4563
Prototype #2
$$('td.second div').each(function(el) { el.setStyle('color : red') });
98.283 5064
Prototype #3
$$('td.second div').invoke('setStyle', 'color : red');
107.81 6070

Comment: Same here, Prototype 2 x faster

4. Adding new elements before every div element which is inside a cell having ’second’ CSS class:

Library Operation Time (ms) Method Calls
jQuery
$('td.second div').before('&lt;h3&gt;text&lt;/h3&gt;')
368.611 15066
Prototype #1
$$('td.second div').each(function(el) { el.insert({ before: '&lt;h3&gt;text&lt;/h3&gt;' }) });
1252.016 17088
Prototype #2
$$('td.second div').invoke('insert', { before: '&lt;h3&gt;text&lt;/h3&gt;' });
1316.969 19096

Comment: Wow…jQuery is almost 4 times faster, I should point out that Element#insert is a new method introduced in Prototype 1.6.0.

5. Removing all div elements which are inside cells having ’second’ CSS class:

Library Operation Time (ms) Method Calls
jQuery
$('td.second div').remove()
151.955 2032
Prototype #1
$$('td.second div').each(Element.remove);
65.785 3060
Prototype #2
$$('td.second div').invoke('remove');
94,105 5068
Prototype #3
$$('td.second div').each(function(el) { el.remove() });
83.591 4062

Comment: Prototype more then 2 times faster.

6. Hiding and un-hiding all div elements which are inside cells having ’second’ CSS class:

Library Operation Time (ms) Method Calls
jQuery
$('td.second div').toggle();$('td.second div').toggle();
1948.825 47653
Prototype #1
$$('td.second div').each(Element.toggle);$$('td.second div').each(Element.toggle);
158.987 14106
Prototype #2
$$('td.second div').each(function(el) { el.toggle() }); $$('td.second div').each(function(el) { el.toggle() });
191.096 16110

Comment: jQuery tragedy, Prototype toggles visibility of 500 divs 10 times faster!

7. Attaching event listeners to all div elements which are inside cells having ’second’ CSS class:

Library Operation Time (ms) Method Calls
jQuery
$('td.second div').bind('click', function(){ alert(this.innerHTML) })
146.19 3535
Prototype #1
$$('td.second div').invoke('observe', 'click', function(){ alert(this.innerHTML) });
169,889 11581
Prototype #2
$$('td.second div').each(function(el) { el.observe('click', function(){ alert(this.innerHTML) }) });
164.456 10575

Comment: no practical difference.

General conclusion and impression

Executed tests show that Prototype seems to be faster then jQuery, with the exception of the new insertion method, which performance should be improved. Although I like jQuery syntax more then Prototype, the performance is way more important then saving few lines of code. Of course tests that I made don’t show how these libraries act in a real application, which is my task for the next part(s) of this article. Despite the results I must admit that I’m very excited about jQuery, my general impression is that this library is more mature then Prototype.

You may want to check out part ||

30Oct/07Off

Why JavaScript helpers in rails are evil

Ruby on Rails gained so much attention and appreciation mostly because it simplifies the development process of AJAX-driven applications. When I started to learn Rails I was already very familiar with other MVC-based frameworks, and actually I’ve created one myself (in PHP5) in my previous work. My framework also uses Prototype JavaScript library, so when l was learning Rails it was nothing new when I saw “Ajax.Updater(…)”. I remember that when I added first AJAX-feature in the Depot (it’s a tutorial application used in well known “Agile Web Development in Ruby on Rails” book) I was shocked about how simple it is, but then I looked into the HTML output and it shocked me once more…

JavaScript Helpers

These nice methods generate for you HTML with some addition of JavaScript code, one can say “You don’t need to know JavaScript to create AJAX web apps! Just use Ruby on Rails!”. It’s a catchy slogan, and in some way it’s true, you don’t need to know how Ajax.Request works, you just write link_to_remote and you’re done. In Rails API you can find 4 helper modules, all related to JavaScript code generation, and here they are:

* General JavaScript Helpers – actually there’s nothing interesting there
* JavaScript Macros Helpers – whole thing is deprecated in the upcoming Rails 2.0
* Prototype Helpers – probably the most popular methods, including link_to_remote and other AJAX goodies
* Scriptaculous Helpers – you know, drag’n'drop and visual effects goodies

When I first saw what link_to_remote helper creates I was really surprised, back then I said to myself “hey, that’s…just bad!”. Unfortunately I had quickly forgotten about my negative thoughts on JavaScript helpers, because “everybody” use them, and that’s a shame in my opinion. I don’t know why JavaScript helpers are included in the Rails core, maybe it was just a pure marketing trick or something :) So, what’s so evil about JavaScript helpers?

DRY - ooooh reaaally?

We, the Ruby on Rails developers, use proudly our favorite MVC framework, we remember everyday about Don’t Repeat Yourself principle and other good and well known practices. How come that people like us write scary pieces of code like this:

<table id="users_list">
  <% @users.each do |user| -%>
  <tr id="user_<%= user.id %>">
    <td><%= user.login %></td>
    <td>
      <%= link_to_remote(
             'Delete',
             :url => user_path(user),
             :method => 'delete',
             :confirm => 'Are you sure?',
             :complete => "Effect.DropOut('user_#{user.id}')",
             :failure => 'alert("Could not delete user: #{user.login}")'
          )
      %>
    </td>
  </tr>
  <% end -%>
</table>
  <% end %>
</table>

Pretty common rhtml snippet, right?? (yes, I know, we use partials, but it’s just an example) Let’s have a look at the HTML output:

<table id="users_list">
    <tr id="user_2">
    <td>jane</td>
    <td>
      <a href="#" onclick="if (confirm('Are you sure?')) { new Ajax.Request('/users/2', {asynchronous:true, evalScripts:true, method: 'delete', onComplete:function(request){Effect.DropOut('user_2')}, onFailure:function(request){alert('Could not delete user: jane')}}); }; return false;">Delete</a>
    </td>
  </tr>
    <tr id="user_1">
    <td>john</td>
    <td>
      <a href="#" onclick="if (confirm('Are you sure?')) { new Ajax.Request('/users/1', {asynchronous:true, evalScripts:true, method: 'delete', onComplete:function(request){Effect.DropOut('user_1')}, onFailure:function(request){alert('Could not delete user: john')}}); }; return false;">Delete</a>
    </td>
  </tr>
    <tr id="user_4">
    <td>paul</td>
    <td>
      <a href="#" onclick="if (confirm('Are you sure?')) { new Ajax.Request('/users/4', {asynchronous:true, evalScripts:true, method: 'delete', onComplete:function(request){Effect.DropOut('user_4')}, onFailure:function(request){alert('Could not delete user: paul')}}); }; return false;">Delete</a>
    </td>
  </tr>
    <tr id="user_3">
    <td>peter</td>
    <td>
      <a href="#" onclick="if (confirm('Are you sure?')) { new Ajax.Request('/users/3', {asynchronous:true, evalScripts:true, method: 'delete', onComplete:function(request){Effect.DropOut('user_3')}, onFailure:function(request){alert('Could not delete user: peter')}}); }; return false;">Delete</a>
    </td>
  </tr>
  </table>

Where did DRY go? Hello? Why we don’t apply our OOP practices also to JavaScript? “Why bother!?” you might ask, well, BECAUSE IT MATTERS.

JavaScript won’t hurt you

Creating webapps without a good understanding of JavaScript is like working with ActiveRecord and having no idea what SQL is. I think you know what I mean. There are plenty of great JavaScript libraries, Ruby on Rails comes with Prototype and it makes writing JavaScript as easy&cool as writing Ruby code. Okey, here’s above example without redundancy, the quickest solution would be:

<table id="users_list">
  <% @users.each do |user| -%>
  <tr id="user_<%= user.id %>">
    <td><%= user.login %></td>
    <td><%= link_to 'Delete', '#', :onclick => "deleteUser(#{user.id})" %></td>
  </tr>
  <% end -%>
</table>

And in application.js (or wherever else):

function deleteUser(userId) {
  if(confirm('Are you sure?') {
    new Ajax.Request(
       '/users/'+userId, {
         method : 'delete',
         on200 : function(){ Effect.DropOut('user_'+userId) },
         on500 : function(xhr){ alert(xhr.responseText) }
    });
  }
  return false;
}

Now, our ouput looks like this:

<table id="users_list">
  <tr>
  <tr id="user_2">
    <td>jane</td>
    <td><a href="#" onclick="deleteUser(2)">Delete</a></td>
  </tr>
  <tr id="user_1">
    <td>john</td>
    <td><a href="#" onclick="deleteUser(1)">Delete</a></td>
  </tr>
  <tr id="user_4">
    <td>paul</td>
    <td><a href="#" onclick="deleteUser(4)">Delete</a></td>
  </tr>
  <tr id="user_3">
    <td>peter</td>
    <td><a href="#" onclick="deleteUser(3)">Delete</a></td>
  </tr>
</table>

Advantages:
* We don’t have a redundant JavaScript code in the HTML output
* We are not limited to what link_to_remote generates
* We have a generic JavaScript function which deletes a user, we can make it even more generic and use successfully in other places

Disadvantages:
* Obtrusive JavaScript code in HTML

Progressive enhancement and unobtrusive JavaScript

I found out about this approach about half a year ago, when I started to use Dan Webb’s UJS rails plugin which makes an extensive use of LowPro library. I was very excited about its functionality, thanks to that plugin I’ve stopped using JavaScript helpers. UJS is a dead project now, you can find out why here but it doesn’t matter, thanks to it I’ve learned two important things:

  • We can divide View layer into two sub-layers: the presentation (HTML+CSS) and the behaviour (JavaScript)
  • Presentation layer can be extended using JavaScript by adding various behaviours to the DOM elements

Currently I don’t use UJS or pure Low Pro, instead I just code my JavaScript using Prototype and Scriptaculous. Let’s see how this looks in practice. Here’s how our users table example could be implemented using progressive enhancement and unobtrusive JavaScript code. First of all, we’re going to create plain HTML links, without onclick event and without even href attribute (I assume we’re writing an application which requires JavaScript to work):

<table id="users_list">
  <% @users.each do |user| -%>
  <tr id="user_<%= user.id %>">
    <td><%= user.login %></td>
    <td><a>Delete</a></td>
  </tr>
  <% end -%>
</table>

Above rhtml template generates this HTML output:

<table id="users_list">
  <tr id="user_3">
    <td>peter</td>
    <td><a>Delete</a></td>
  </tr>
  <tr id="user_4">
    <td>paul</td>
    <td><a>Delete</a></td>
  </tr>
  <tr id="user_1">
    <td>john</td>
    <td><a>Delete</a></td>
  </tr>
  <tr id="user_2">
    <td>jane</td>
    <td><a>Delete</a></td>
  </tr>
</table>

The very last thing to do is to add an actual functionality to our plain HTML code. Let’s create a simple module called Users, which will include method for deleting users:

var Users = {
  onWindowLoad : function() {
    $('users_list').getElementsBySelector('tr').each(function(userRow){
      userRow.down('a').observe('click', Users.onUserDelete);
    });
  },
  onUserDelete : function(event) {
    if(confirm('Are you sure?')) {
      var userId = Event.element(event).up('tr').id.split('_').last();
      new Ajax.Request(
       '/users/'+userId, {
         method : 'delete',
         on200 : function(){ Effect.DropOut('user_'+userId) },
         on500 : function(xhr){ alert(xhr.responseText) }
      });
    }
  }
}
Event.observe(window, 'load', Users.onWindowLoad);

This way we:

  • Write reusable and object oriented code
  • Create clean and easy to maintain RHTML templates
  • Have a clean separation between visual and behavior layers in our applications
  • Decrease site loading time by writing less JavaScript (you can even compress it too)
  • Improve general performance of our application’s UI
  • Learn JavaScript! :)

The final word

I didn’t write anything about so called graceful degradation issue, leaving JavaScript helpers behind was the main reason for this article. If you totally disagree with me or/and you know an even better approach, leave a comment, I’m always open to a discussion.