Tuesday, March 20, 2007

Javascript String Performance

Followup previous article on innerHTML performance, I now take a look at what is the better way to built the HTML string for the innerHTML.

I use 2 for loop to built a table with 1000 rows and 5 columns. 4 different ways of building the string is tested. The test is done on Firefox 2.

1) str += ...
2) str = str + ...
3) str = str.concat(... , ...)
4) str.push(... , ...)

Below is the javascript sample for the 4th test cases

function init(){
var newStr = new Array("<table>");
for(var i=0; i<1000; i++){
for (var j=0; j<5; j++){
newStr.push("<td>row ", i, " col ", j, "</td>");
document.getElementById("content").innerHTML = newStr.join("");

I did sample of 20 time and get the average result.

Test TypeAverage Time (ms)
1str += ...317.5
2str = str + ...285.4
3str = str.concat(... , ...)287.2
4str.push(... , ...)298.4

The results is quite close. The 1st Case is the slowest among all. The other 3 time is almost silimar considering their performance variation is about the same. Thus for most case (small functions), either way should be fine. But to squeeze every ms out, try using case 2-4.

The only thing to avoid is building the string like the example below.
newStr = newStr + "row ";
newStr = newStr + i;
newStr = newStr + " col ";
newStr = newStr + j;
newStr = newStr + "";

Use this instead:
newStr = newStr + "row " + i + " col " + j + "";

Any String that can be build in one line, should be done so.

Add to del.icio.us


Thomas Bahn said...

Hi William,

but why would you built the HTML presentation of the table in JavaScript? Wouldn't it be better to let the server do this?

Most often you would get the data for the table from the server anyway. Since it is tabular data, it most probable, that it is data from a view. Considering (runtime) performance, I would propose a view, that generates the headers and table cells, and a $$ViewTemplate form (or a form embedding the view) for the rest.


William Beh said...

@Thomas. Yes, in Domino, it would be faster to use a view & $$ViewTemplate to built a html table. But there are many cases where you have to built dynamic html on the fly. For example dynamic input table. But for most cases these won't need a large set of HTML for the job. This post example is to test how to maximized our javascript codes.

Tommy Valand said...

It's also useful when using Ajax (don't know if that was what you meant with dynamic input table).

Either convert XML, JSON or whatever to HTML.

With big forms/applications with a lot of users, it can save a lot of bandwidth/system resources on the server.

Thomas Bahn said...

Ajax is the perfect use-case for the view generating the HTML I mentioned in my comment.

Think of a really simple case
1: One
2: Two
3: Three

You could build a view with
1st column: "<tr><td>" + NumberNumber + "</td>"
2nd column: "<td>" + NumberName + "</td></tr>"

Then a Ajax-call to the view would get something like:

Then you would replace the content of a div with id="MyTable":
mytable = document.getElementById("MyTable");
mytable.innerHTML = "<table>" + request.responseText + "</table>";

This way you could benefit of the view caching of the Domino server.


William Beh said...

@Tommy. Ajax is definitely useful. A very simple case is for categorized view. Domino default do a refresh with every expand/collapse or next/previous navigation of the view. Ajax can be used to pull and display the required html.

Dynamic input table is building a dynamic multiple row input table. For example a product group can have multiple products (id, name, etc input fields). The user can have flexibility to add or remove product entry in a form. A table may have to be generated to display existing products of the group document. Another way to do it is to store the products in a separate form. Use Ajax to save to user input into the form and pull the display table from the view.

There are cases where you want to use existing view instead of creating new view. For a very large indexed database, you may want to reduce the number of views. So using ?ReadViewEntries to retrieve data and dynamically generating the view is an option.