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

kick it on DotNetKicks.com