Preface
I think everyone would agree that AJAX is one of the elements of "Web 2.0", every web developers should know this technology. I have been collected a list of the popular AJAX Frameworks on my chinese tech blog, we will amazedly found that, there are more than 128 AJAX Frameworks!
Refer to a voting result, among the 95% of the .NET developers that said they are using some flavor of Ajax either in production, development or prototype, the most used AJAX Framework is ASP.NET AJAX, with 73,7%, followed by the Ajax Control Toolkit which is used by almost half of the .NET developer that are using Ajax.
However, many beginners always complain that, using ASP.NET AJAX make their web application slow down, don't perform as well as they had hoped.
Today, I would like to share some experience on how to optimize the ASP.NET AJAX application.
So I created a simple page with a bunch of extenders on it: CalendarExtender, SliderExtender, NumericUpDownExtender, RoundedCornersExtender, and TabContainer for our experiments.
And I would like to introduce two useful tools for our Performance Analysis:
1. HttpWatch to show the network traffic.
Here's how the network traffic looked before any optimization: And we can see there are totally 22 requests and spend 9 seconds to get the 654k result. It is a really terrible in performance.
2. ScriptReferenceProfiler to show the JavaScript reference.
ScriptReferenceProfiler is an open source tool on CodePlex, for analysis the JavaScript references of ASP.NET AJAX, we can simply add the following code to our page in order to show the JavaScript references imported by ScriptManager.
</microsoft:scriptreferenceprofiler>
We can see, before any optimization, there are 17 references found on this page, include the Microsoft Ajax Core runtime, asynchronous postback scripts, Ajax Control Toolkit Extender scripts and so on:
Optimization in web.config
To optimize the ASP.NET AJAX in our web application, first of all, we need to make sure the Compression and Caching is enabled in our web.config:<system.web.extensions>
<scripting>
<scriptResourceHandler enableCompression="true" enableCaching="true"/>
</scripting>
</system.web.extensions>
1. Enable The Caching:
We know, in the development of web application, enable the caching is a must operation.
To enable the caching of ASP.NET AJAX, we need make sure the enableCaching property of scriptResourceHandler is set to true.
As our expected, the page response more quickly in the second time, the expend time is coming from 12.862 seconds down to 0.409seconds; and the received size from server decrease from 692K to 14K.
2. Enable The Compression:
The Caching will saving almost 95% of the network traffic in the second time we request the page, however, the first page request still ask for a huge data from server. How to reduce the first request? don't worry, set enableCompression property of scriptResourceHandler to true will help:
As we can see in the screen shot, many script files are getting smaller. and the total size decrease form 692K to 183K, about 1/4 compare to before.
♣Note: The compression is not work in Internet Explorer 6.0, because there is an known bug in IE 6, that cause the mistake might be occur when receiving the Gzip header. So the develop team close all the compression ability in IE 6.
Optimization in ScriptManager
The ScriptManager control manages client script for AJAX-enabled ASP.NET Web pages. By default, the ScriptManager control registers the script for the Microsoft AJAX Library with the page. This enables client script to use the type system extensions and to support features such as partial-page rendering and Web-service calls.
Following, we need to setting the property of ScriptManager to optimize the performance of ASP.NET AJAX.
1. ScriptMode for Release
In one of Scott Guthrie's post, he explain that we should avoid when deploying an ASP.NET application into production leave the <compilation debug=”true”/> switch on within the application’s web.config file.
It will cause:
1) The compilation of ASP.NET pages takes longer (since some batch optimizations are disabled)
2) Code can execute slower (since some additional debug paths are enabled)
3) Much more memory is used within the application at runtime
4) Scripts and images downloaded from the WebResources.axd handler are not cached
In this scenario, we can set the ScriptManager on the page run into the release mode to like the following:
<asp:ScriptManager ID="ScriptManager1" runat="server" ScriptMode="Release">
</asp:ScriptManager>
2. EnablePartialRendering Yes or No?
There is another property in ScriptManager named EnablePartialRendering, it gets or sets a value that enables partial rendering of a page, which in turn enables you to update regions of the page individually by using UpdatePanel controls.
So, if we using the UpdatePanel in the page, we must set this property to true, conversely, if the UpdatePanel is not using in our page, it would be better that we set the EnablePartialRendering to false.
That will cause the unnecessary file "MicrosoftAjaxWebForm.js", which is used to the partial rendering not import to our page.
<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePartialRendering="false">
</asp:ScriptManager>
3. LoadScriptBeforeUI
ScriptManager control has LoadScriptsBeforeUI property which we can set to “False” in order to postpone several script downloads after the content is downloaded and shown. This adds the script references end of the <body> tag.
As a result, we will see the content first and then the additional scripts, exteders, AJAX Control Toolkit scripts get downloaded and initialized.
This will make the page show quikly, and provide a better User Experience.
Script Combining
In the previous talk, we can see the download size is coming down, but the number of requests is still more than 201. ToolkitScriptManager
There is a ToolkitScriptManager control in the AJAX Control Toolkit, we can replace the default <asp:scriptmanager> control with this, it supports the ability to dynamically merge multiple client-side Javascript scripts into a single file that is downloaded to the client at runtime.
Better yet, only the Javascript needed by the specific controls on the page are included within the combined download, to make it as small as possible.
As the screen shot shows, It is a big savings in requests - we now get one request for Toolkit scripts instead of 12.
In this scenario, we also got about a 50% download speed improvement by only having one request.
2. CompositeScript
If you are using ASP.NET 3.5 with SP1, there is a more powerful tool to combining the Script file - CompositeScript.
First, We can use the ScriptReferenceProfiler to show the JavaScript references and then, we can add <CompositeScript> and <Scripts> elements as children of the ScriptManager control.
Then, Copy the script references from the page and paste them into the <Scripts> element inside the ScriptManager control, the result mark up is following:
<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePartialRendering="false" ScriptMode="Release" LoadScriptsBeforeUI="false">
<CompositeScript>
<Scripts>
<asp:ScriptReference Name="MicrosoftAjax.js" />
<asp:ScriptReference Name="AjaxControlToolkit.Common.Common.js" Assembly="AjaxControlToolkit, Version=3.0.20229.23352, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e" />
<asp:ScriptReference Name="AjaxControlToolkit.ExtenderBase.BaseScripts.js" Assembly="AjaxControlToolkit, Version=3.0.20229.23352, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e" />
<asp:ScriptReference Name="AjaxControlToolkit.Tabs.Tabs.js" Assembly="AjaxControlToolkit, Version=3.0.20229.23352, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e" />
<asp:ScriptReference Name="AjaxControlToolkit.DynamicPopulate.DynamicPopulateBehavior.js"
Assembly="AjaxControlToolkit, Version=3.0.20229.23352, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e" />
<asp:ScriptReference Name="AjaxControlToolkit.Common.DateTime.js" Assembly="AjaxControlToolkit, Version=3.0.20229.23352, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e" />
<asp:ScriptReference Name="AjaxControlToolkit.Compat.Timer.Timer.js" Assembly="AjaxControlToolkit, Version=3.0.20229.23352, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e" />
<asp:ScriptReference Name="AjaxControlToolkit.Animation.Animations.js" Assembly="AjaxControlToolkit, Version=3.0.20229.23352, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e" />
<asp:ScriptReference Name="AjaxControlToolkit.Animation.AnimationBehavior.js" Assembly="AjaxControlToolkit, Version=3.0.20229.23352, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e" />
<asp:ScriptReference Name="AjaxControlToolkit.PopupExtender.PopupBehavior.js" Assembly="AjaxControlToolkit, Version=3.0.20229.23352, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e" />
<asp:ScriptReference Name="AjaxControlToolkit.Common.Threading.js" Assembly="AjaxControlToolkit, Version=3.0.20229.23352, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e" />
<asp:ScriptReference Name="AjaxControlToolkit.Calendar.CalendarBehavior.js" Assembly="AjaxControlToolkit, Version=3.0.20229.23352, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e" />
<asp:ScriptReference Name="AjaxControlToolkit.Compat.DragDrop.DragDropScripts.js"
Assembly="AjaxControlToolkit, Version=3.0.20229.23352, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e" />
<asp:ScriptReference Name="AjaxControlToolkit.Slider.SliderBehavior.js" Assembly="AjaxControlToolkit, Version=3.0.20229.23352, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e" />
</Scripts>
</CompositeScript>
</asp:ScriptManager>
Run the page and view the traffic. We will see just one script reference now instead of all the script inside the <Scripts> element.
References:
1. Microsoft WebCast by Jeffery Zhao
2. ASP.NET Ajax in-depth performance analysis by Omar
3. Using Script Combining to improve AJAX performance by Betrand Le Roy
Thanks!