Hi there,
In my series of 'Performance with ASP.NET AJAX & Client Repeater Control', which I started about two weeks ago, now it is already time for part 3 of the series, namely: Performance with ASP.NET AJAX & Client Repeater Control - Part 3 - DOM Create element.
These are the articles that I will soon be writing about or already have written about:
- Performance with ASP.NET AJAX & Client Repeater Control - Part 4 - String Concatenation
Things in this solution are a little bit different compared to the Server side Repeater control and updatepanel approach. The overall aspect is exact the same as written in part 2 of the series, except for the client-side code to built the results table.
These are the things I have done (which can be seen when you download the source files below):
1. Setting up a page with a generate data button to retrieve a set of 3000 person records
2. Setting up a local webservice that will get the data (could have been a PageMethod).
3. Invoking the webservice from client script
4. Cathing the results and build a client repeater using the DOM document.CreateElement methods.
So this is how initially my page looks:

When invoking the 'Generate data button', a client side script is invoked, that on its turn will call the local webservice, which was referenced as a script resource in the scriptmanager. The local webservice is called that returns the 3000 person records (I wanted a large resultset, so you could see that the performance issues arise when using an updatepanel as in my previous post). When the data was retrieved from the local webservice it is handled in client script by making use of the DOM document.CreateElement method.
This is the call to the local webservice:
PersonService.GeneratePersons(onSuccess, onFailed);
This is the javascript used to make up the table:
function BuildTable(results) {
var table = document.createElement('table');
var body = document.createElement('tbody');
var tr = document.createElement('tr');
var tdId = document.createElement('td');
tdId.setAttribute("width", "100px");
tdId.setAttribute("valign", "top");
tdId.setAttribute("align", "left");
tdId.innerHTML = "Id";
var tdName = document.createElement('td');
tdName.setAttribute("width", "100px");
tdName.setAttribute("valign", "top");
tdName.setAttribute("align", "left");
tdName.innerHTML = "Name";
var tdLastname = document.createElement('td');
tdLastname.setAttribute("width", "100px");
tdLastname.setAttribute("valign", "top");
tdLastname.setAttribute("align", "left");
tdLastname.innerHTML = "Lastname";
var tdAge = document.createElement('td');
tdAge.setAttribute("width", "100px");
tdAge.setAttribute("valign", "top");
tdAge.setAttribute("align", "left");
tdAge.innerHTML = "Age";
var tdBlog = document.createElement('td');
tdBlog.setAttribute("width", "100px");
tdBlog.setAttribute("valign", "top");
tdBlog.setAttribute("align", "left");
tdBlog.innerHTML = "Blog";
tr.appendChild(tdName);
tr.appendChild(tdName);
tr.appendChild(tdLastname);
tr.appendChild(tdAge);
tr.appendChild(tdBlog);
body.appendChild(tr);
for (var Person in results) {
var tableRow = document.createElement('tr');
var tdInnerId = document.createElement('td');
tdInnerId.setAttribute("width", "100px");
tdInnerId.setAttribute("valign", "top");
tdInnerId.setAttribute("align", "left");
tdInnerId.innerHTML = results[Person].id;
var tdInnerName = document.createElement('td');
tdInnerName.setAttribute("width", "100px");
tdInnerName.setAttribute("valign", "top");
tdInnerName.setAttribute("align", "left");
tdInnerName.innerHTML = results[Person].name;
var tdInnerLastname = document.createElement('td');
tdInnerLastname.setAttribute("width", "100px");
tdInnerLastname.setAttribute("valign", "top");
tdInnerLastname.setAttribute("align", "left");
tdInnerLastname.innerHTML = results[Person].lastname;
var tdInnerAge = document.createElement('td');
tdInnerAge.setAttribute("width", "100px");
tdInnerAge.setAttribute("valign", "top");
tdInnerAge.setAttribute("align", "left");
tdInnerAge.innerHTML = results[Person].age;
var tdInnerBlog = document.createElement('td');
tdInnerBlog.setAttribute("width", "100px");
tdInnerBlog.setAttribute("valign", "top");
tdInnerBlog.setAttribute("align", "left");
tdInnerBlog.innerHTML = results[Person].blog;
tableRow.appendChild(tdInnerId);
tableRow.appendChild(tdInnerName);
tableRow.appendChild(tdInnerLastname);
tableRow.appendChild(tdInnerAge);
tableRow.appendChild(tdInnerBlog);
body.appendChild(tableRow);
}
table.appendChild(body);
$get('clientrepeater').appendChild(table);
}
So looking at the following results you'll see the benefit of using the client side StringBuilder compared to the server-side Repeater variant in combination with the updatepanel and compared to using the DOM document.CreateElement methods:
REQUEST 1 - The Updatepanel: 1531 miliseconds
REQUEST 2 - The Updatepanel: 8469 miliseconds
REQUEST 3 - The Updatepanel: 8672 miliseconds
REQUEST 4 - The Updatepanel: 8437 miliseconds
REQUEST 5 - The Updatepanel: 8766 miliseconds
REQUEST 1 - StringBuilder: 6562 miliseconds
REQUEST 2 - StringBuilder: 6859 miliseconds
REQUEST 3 - StringBuilder: 6781 miliseconds
REQUEST 4 - StringBuilder: 6938 miliseconds
REQUEST 5 - StringBuilder: 6906 miliseconds
REQUEST 1 - DOM document.CreateElement: 7266 miliseconds
REQUEST 2 - DOM document.CreateElement: 7032 miliseconds
REQUEST 3 - DOM document.CreateElement: 7797 miliseconds
REQUEST 4 - DOM document.CreateElement: 7734 miliseconds
REQUEST 5 - DOM document.CreateElement: 9078 miliseconds
So overall there's a 0,5 second performance loss when using the DOM document.CreateElement at the client compared to the solution when using the StringBuilder.
If you want to take a look for yourself, you can find the source code here (VS 2008, .NET Framework 3.5) (Ofcourse the results may vary depending on CPU en PC memory):
AjaxPerformance - DOM CreateElement.zip (9,20 kb)
I'm off for my next article 'Performance with ASP.NET AJAX & Client Repeater Control - Part 4 - String Concatenation' See ya!
Hope this is usefull!
gr,
Robbert