This is a migrated thread and some comments may be shown as answers.

Client-side performance on WSS and FF/IE

3 Answers 78 Views
General Discussions
This is a migrated thread and some comments may be shown as answers.
Mikael
Top achievements
Rank 1
Mikael asked on 14 Sep 2008, 02:26 PM
I have noticed a rather dramatic client-side performance difference, depending if the Telerik control is hosted in an ordinary ASP.NET page or in a WSS page. Also, the rendering time is very different depending on the browser, FF 3 is much faster than IE7.

I have a test-case where rendering in WSS is ~4 times slower than in ASP.NET. And FF3 is up to 5 times faster than IE7 in the same test.

Here's some data for rendering a RadTreeView-control with 1365 nodes:
WSS, IE7: 20 secs
ASP.NET, IE7: 6 secs
WSS, FF3: 4 secs
ASP.NET, FF3: 2,7 secs
(I know it's not advisable with so many nodes in a tree, but it makes the performance difference more obvious).

This is just one case where the difference is obvious. All my test-cases, including RadTreeView and RadGrid, shows similar performance.

Can anyone explain why rendering is so much slower in WSS than ASP.NET, and why IE7 is so much slower than FF3?

At first, I thought it could be because, in WSS, the Rad-control lives "deeper" in the DOM, since a WSS-page is filled with tables-in-tables-in-divs-etc-etc. Lots of Telerik-script walks up the DOM using constructs like this:

while (node)
{
    if (dosometest(node)) return true;
    node = node.parentNode;
}
return false;


This could explain the performance difference, since the script would walk all the way up to the DOM-root if dosometest returns false. I turns out that this does not explain the ASP.NET/WSS performance difference, I manually added nested DIVs in an ASP.NET page, to simulate a WSS-page's depth, and there was still a huge performance difference. Nevertheless, perhaps Telerik should consider a more clever condition to test for than while(node), to reduce iterating the DOM-tree unnessarily.

For the IE7 vs FF3 difference, I have no idea why this is.

It would be interesting to know the reason for these differences, but of course much more interesting to know if there's a work-around.

I can provide the code that generates the data above. I should mention that rendering takes place async, I use ASP.NET's UpdatePanel.

/Fredrik

3 Answers, 1 is accepted

Sort by
0
Dimitar Milushev
Telerik team
answered on 15 Sep 2008, 12:59 PM
Hi Fredrik,

There are many factors that affect the client-side performance and contribute to the difference between the WSS and vanilla ASP.NET scenarios. You are right that one of the reasons is the nesting of the DOM, but it's not only the depth of the nesting - tables tend to be significantly slower than DIVs for DOM operations in IE. Also, in IE the size of the entire DOM tree affects the speed of DOM operations. So the more HTML elements you have on the page, the slower Javascript execution becomes. Unfortunately, there is not much we can do about this.

As for the difference between FF3 and IE7 - not all browsers are created equal. Visual rendering, DOM operations, overall Javascript performance, etc. is faster Firefox. Testing with Opera will probably show even larger difference.

While performing slower in WSS, I hope both RadTreeView and RadGrid perform well enough in your real-life scenario. We are constatly working to improve both the server-side and client-side performance of all RadControls so make sure you conduct such performance tests with the latest official versions.

Best wishes,
Dimitar Milushev
the Telerik team

Check out Telerik Trainer, the state of the art learning tool for Telerik products.
0
Mikael
Top achievements
Rank 1
answered on 16 Sep 2008, 07:50 AM
Thanks for your response, Dimitar.

In my opinion your controls provide great features and your support is world-class. Still, I am a little worried that client-side performance of the controls will stop us from building the UIs we want.
We already suffer from performance problems, although our UI is currently very simple. Granted, we have some optimizations to do, but the fact that our UI is not nearly as complex as it will be, makes me a little worried for the future.

Note that for me, initial page load-time is not a problem, only a fraction of the time is spent there. Instead, it is the client-side script that puts the CPU at 100%, for seconds in some cases. Perhaps you should invest more time in trying to optimize your client-side performance. For instance, do you have a comment on the script I sent below. Isn't there room for optimization there? 
You could also give more advice on how to improve client-side performance. Currently, your optimization tips, although helpful, mostly discusses page load-time.
Finally, tips on how to profile client-side performance in IE would be great. Firebug in FF3 works great, but I haven't found any such tool for IE. Ajax View looks really promising (http://research.microsoft.com/projects/ajaxview/), but I haven't managed to get it to give meaningful numbers yet.

I am attaching a script that at least measures the time between different "ajax life-cycle events" at the bottom of this mail. The time between beginRequest and pageLoading is the time for performing an AJAX postback whereas the time between pageLoading and pageLoaded is the time for rendering.  .

Thanks,

/Fredrik

 <div>
                <table style="border-collapse:collapse" border="1">
                    <thead>
                        <tr>
                            <th scope="col" align="left">Time (ms)</th>
                            <th scope="col" align="left">Event</th>
                            <th scope="col" align="left">Details</th>
                        </tr>
                    </thead>
                    <tfoot>
                        <tr>
                            <td align="left" colspan="3">                               
                                <a href="#" onclick="clearEvents();">Clear&nbsp;
                                    <asp:Image id="Clear" runat="server" ImageUrl="~/images/trashcan.gif"
                                     ImageAlign="AbsBottom" AlternateText=""/>
                                 </a>                       
                            </td>
                        </tr>
                    </tfoot>
                    <tbody id="clientEvents">
                    </tbody>
                </table>               
            </div>

            <!-- Asynchronous postback cue for users -->
            <div id="loadingPanel" class="asyncPostBackPanel" style="display: none;">
                <img src="images/indicator.gif" alt="" />&nbsp;&nbsp;Loading...
            </div>

<script type="text/javascript">

   // Register handlers for Application model events
   Sys.Application.add_init(onInit);
   Sys.Application.add_load(onLoad);

   // Registern handlers for PageRequestManager events
   with(Sys.WebForms.PageRequestManager.getInstance()) {
     add_initializeRequest(onInitializeRequest);
     add_beginRequest(onBeginRequest);
     add_pageLoading(onPageLoading);
     add_pageLoaded(onPageLoaded);
     add_endRequest(onEndRequest );
    }  

   // Init event - raised by Sys.Application
   function onInit(sender, args){                  
    var row = createEventRow("init", "", requestInitialized);
    $get('clientEvents').appendChild(row);      
   }

   // Load event - raised by Sys.Application
   function onLoad(sender, args){                       
    var details;
    if (!args.get_isPartialLoad()){
     details = "Normal postback";
    }
    else{
     details = "Asynchronous postback";
    }
         
    var row = createEventRow("load", details, requestInitialized);
    $get('clientEvents').appendChild(row);
   }
     
   var requestInitialized = null;

   // initializeRequest event - beginning stages of a request, raised to
   // give us an opportunity to cancel or aborted postbacks.
   function onInitializeRequest(sender, args){   
       var date = new Date();
    requestInitialized = date.getTime();                           

    var prm = Sys.WebForms.PageRequestManager.getInstance();
    var details = "postBackElementID = " + args.get_postBackElement().id;
     
    // Check to see if we're in an asychronous postback   
    if (prm.get_isInAsyncPostBack()){
         
     // Aborting a postback will stop the request from happening and
     // no updates will be applied.
     if (args.get_postBackElement().id == "Abort"){    
      Sys.WebForms.PageRequestManager.getInstance().abortPostBack();       
      details += " (aborted)";
     }
     else{
             
      // Canceling a postback means that the previous postback will
      // continue to be processed, otherwise the most recent postback
      // will be handled instead.
      args.set_cancel(true);
      details += " (canceled)";
     }
    }
        
    var row = createEventRow("initializeRequest", details, requestInitialized);
    $get('clientEvents').appendChild(row);                         
   }

   // beginRequest event - This is raised just before the request is sent to the server
   function onBeginRequest(sender, args){          
     
    // Show the user some visual cue that we are processing an
    // asynchronous request. Also, we only want to show this for
    // the longer operations, such as when the SlowUpdate button
    // is the element that invoked the postback.
    if (args.get_postBackElement().id == "SlowUpdate"){               
     $get('loadingPanel').style.display = 'block';
    }
                                                         
    var row = createEventRow("beginRequest", "", requestInitialized);
    $get('clientEvents').appendChild(row);         
   }
         
   // pageLoading event - raised after the postback has been processed on
   // the server but before updates to the user interface are applied.
   function onPageLoading(sender, args){        
     
    // Retrieve the list of UpdatePanel controls that are being
    // updated or deleted.
    var details = new Sys.StringBuilder();
    details.append(displayPanels("Updating", args.get_panelsUpdating()));       
    details.append("  -  ");
    details.append(displayPanels("Deleting", args.get_panelsDeleting()));                                 
    var row = createEventRow("pageLoading", details.toString(), requestInitialized);
    $get('clientEvents').appendChild(row);       
   }
         
   // pageLoaded event - raised after the updates have been applied
   // to the user interface.
   function onPageLoaded(sender, args){  
     
    // Retrieve the list of UpdatePanels that were created and updated.
    var details = new Sys.StringBuilder();
    details.append(displayPanels("Created", args.get_panelsCreated()));
    details.append("  -  ");
    details.append(displayPanels("Updated", args.get_panelsUpdated()));   
    var row = createEventRow("pageLoaded", details.toString(), requestInitialized);
    $get('clientEvents').appendChild(row);       
   }
         
   // endRequest event - raised after the load event of the Sys.Application
   // object to signify the end of an asychronous postback.
   function onEndRequest(sender, args){                
     
    // This event is always raised, even when an error occurs on the server.
    var details = "";
    var error = args.get_error();
    if (error != null){
       details = "Error: " + error.message;
     args.set_errorHandled(true);
    }
    else
     details = "No errors";           
         
    // Hide visual cue of asynchronous postback
    $get('loadingPanel').style.display = 'none'; 
    var row = createEventRow("endRequest",  details, requestInitialized);
    $get('clientEvents').appendChild(row);                   
    requestInitialized = null;
   }

   // Helper function for creating a new row
   // in the event viewer table.
   function createEventRow(eventName, details, requestInitialized){
                         
    var row = document.createElement("tr");

  
    var duration = " ";
    if (requestInitialized != null)
    {
        var date = new Date();
     duration = date.getTime() - requestInitialized;
    }

    var timeCell = document.createElement("td");
    var timeText = document.createTextNode(duration);
    timeCell.appendChild(timeText);
    row.appendChild(timeCell);
         
    var eventCell = document.createElement("td");
    var eventText = document.createTextNode(eventName);
    eventCell.appendChild(eventText);
    row.appendChild(eventCell);
                     
    var detailsCell = document.createElement("td");
    var detailsText = document.createTextNode(details);
    detailsCell.appendChild(detailsText);
    row.appendChild(detailsCell);       

    return row;      
   }

   // Helper method that will format some information
   // about the update panels in the pageLoaded and
   // pageLoading events.
   function displayPanels(action, panels){           
    var sb = new Sys.StringBuilder();
    sb.append(action + " " + panels.length + " panel");
    if (panels.length == 0 || panels.length > 1)
     sb.append("s");
         
    if (panels.length > 0){              
     sb.append(" (");
     for (var i = 0; i < panels.length; i++){
      if (i > 0)
       sb.append(", ");
                     
      sb.append(panels[i].id);
     }
     sb.append(")");             
    }       
    return sb.toString();
   }   

   // Helper method to clear the events in the
   // event viewer table.
   function clearEvents(){
    var events = $get('clientEvents');           
    while (events.firstChild) {
     events.removeChild(events.firstChild);
    }     
   }
  </script>

0
Dimitar Milushev
Telerik team
answered on 18 Sep 2008, 02:33 PM
Hello Fredrik,

Can you please open a support ticket and send us the Web Part that is causing the described performance issues? I'd like to profile it locally and see what exactly is causing the slowdown.

Regards,
Dimitar Milushev
the Telerik team

Check out Telerik Trainer, the state of the art learning tool for Telerik products.
Tags
General Discussions
Asked by
Mikael
Top achievements
Rank 1
Answers by
Dimitar Milushev
Telerik team
Mikael
Top achievements
Rank 1
Share this question
or