What is ScriptCombining? It's all about network latency. Conventional thinking was to break apart script files into small chunks so that the browser only needs to download the minimal set required. The idea was great, and it could even have a positive impact on your application, until the laws of the internet start to interfere. The problem is that each script file must initiate a connection to the server. Connections have some degree of overhead involved from the aspect of the server, so splitting a file in 2 and serving it up over 2 requests instead of one, will take slightly longer. But that's nothing compared to the effects of network latency.
Latency, is the minimum time it takes for a packet to travel from one location to the next. We're all familiar with the idea of latency, as it's clearly evident when you're speaking on the phone to someone across the world. Think of the delay before they hear what you said, and vice-versa. The same laws of physics apply to HTTP connections. For HTTP, the latency is assessed per connection. So for every connection your site makes back to the server during a page load (or partial AJAX load), your load time increases by a given number. If we go back to our phone conversation analogy, there's no noticeable delay while you're talking, but think about what happens each time you stop talking and wait for a response from the other side. Those delays are all additive, just like in our HTTP request/response pairs.
To put this to some hard numbers, imagine your site has 30 'objects' on the page. An object is something that requires making a connection to the server - this could be a javascript file, an Image, a flash video, or even a stylesheet. Now let's imagine some unfortunate soul on the other side of the world is viewing your site, or running your web application. If their average latency is 300ms, you're talking about a minimum page load time of 4.5 seconds based on the browsers ability to have 2 simultaneous connections (300ms/roundtrip * 9 connections /2 connections per roundtrip) = 4.5 seconds
If you want to simulate this in an ASP.NET application, add a HTTPModule to your application and insert a System.Threading.Thread.Sleep(300) into the BeginRequest event. Now for each request made to your application, there will be a 300ms delay representing the latency.
So what about the effects of browser caching? Javascript files along with CSS and Images are all cached resources for a browser. As long as these items are in the browse's cache, the client does not need to initiate a request (http connection) with the server, which means no latency penalty is incurred. Tip: When setting cache headers, remember that using a conditional request (If-Modified-Since header) will still require an HTTP connection. Stick with Expires or Cache-Control headers, which will alleviate the need for any HTTP connection once the item has been added to the cache. Learn more about caching from w3.org. You can set the cache characteristics of specific filetypes through your webserver, or by adding response headers dynamically.
A recent study published from yahoo though, shows an astonishing 20% of page views are done with an empty cache. While that number seems high, it certainly points out that empty cache visits are not edge case, and should be given some attention. Besides, we all know how important first impressions are, so even if your application only loads slow the first time a user visits, that may also be the last time.
It should be pretty clear now that latency has a significant impact on your web site/application performance. And the to make matter worse, it's not something that you're likely to notice during testing since your latency will be minimal. That's why defensive programming is a priority here. And it's not that difficult either..
Download an HTTP monitor like Fiddler (http://www.fiddlertool.com/fiddler/version.asp) Use the tool to examine how many connections are made during an empty and full cache request.
Minimize the total number of HTTP requests by combining separate script or css files into a single file. There are utilities out there to combine CSS files and even shorten class names. If you're using ASP.NET 3.5 SP1 you can combine Javascript resources by using the ScriptManager's CompositeScript element. Simply add each script element as part of a "CompositeScript" and the ScriptManager will do the combining for you. This is especially useful when you're using 3rd party tools which may contain embedded resources, and there's no actual script file to work with. Here's how to get started..
Download the ScriptReferenceProfiler.
Copy the assembly into your bin directory, and add a reference to your page with the following tag:
<%@ Register TagPrefix="scriptSvc" Namespace="ScriptReferenceProfiler" Assembly="ScriptReferenceProfiler, Version=1.1.0.0, Culture=neutral" %>
Now add the ScriptReferenceProfiler control to your web form by pasting the following tag into your "Form" tag
<scriptSvc:ScriptReferenceProfiler runat="server" ID="sp" />
Now view your page in the Browser and copy the references which are emitted at the top of the page into the clipboard. If you're using the WebDataGrid, you should end up with something like:
<asp:ScriptReference Name="MicrosoftAjax.js" /> <asp:ScriptReference Name="MicrosoftAjaxWebForms.js" /> <asp:ScriptReference Name="Infragistics.Web.UI.Scripts.0_igControlMain.js" Assembly="Infragistics35.Web.v8.3, Version=8.3.20083.169, Culture=neutral, PublicKeyToken=7dd5c3163f2cd0cb" /> <asp:ScriptReference Name="Infragistics.Web.UI.Scripts.2_igCollections.js" Assembly="Infragistics35.Web.v8.3, Version=8.3.20083.169, Culture=neutral, PublicKeyToken=7dd5c3163f2cd0cb" /> <asp:ScriptReference Name="Infragistics.Web.UI.Scripts.3_igUIBehaviors.js" Assembly="Infragistics35.Web.v8.3, Version=8.3.20083.169, Culture=neutral, PublicKeyToken=7dd5c3163f2cd0cb" /> <asp:ScriptReference Name="Infragistics.Web.UI.Scripts.4_igEnums.js" Assembly="Infragistics35.Web.v8.3, Version=8.3.20083.169, Culture=neutral, PublicKeyToken=7dd5c3163f2cd0cb" /> <asp:ScriptReference Name="Infragistics.Web.UI.Scripts.5_igObjects.js" Assembly="Infragistics35.Web.v8.3, Version=8.3.20083.169, Culture=neutral, PublicKeyToken=7dd5c3163f2cd0cb" /> <asp:ScriptReference Name="Infragistics.Web.UI.Scripts.7_igClientStateManager.js" Assembly="Infragistics35.Web.v8.3, Version=8.3.20083.169, Culture=neutral, PublicKeyToken=7dd5c3163f2cd0cb" /> <asp:ScriptReference Name="Infragistics.Web.UI.Scripts.8_igCallback.js" Assembly="Infragistics35.Web.v8.3, Version=8.3.20083.169, Culture=neutral, PublicKeyToken=7dd5c3163f2cd0cb" /> <asp:ScriptReference Name="Infragistics.Web.UI.Scripts.9_igPropertyManagers.js" Assembly="Infragistics35.Web.v8.3, Version=8.3.20083.169, Culture=neutral, PublicKeyToken=7dd5c3163f2cd0cb" /> <asp:ScriptReference Name="Infragistics.Web.UI.GridControls.WebDataGrid.js.igWebDataGridBase.js" Assembly="Infragistics35.Web.v8.3, Version=8.3.20083.169, Culture=neutral, PublicKeyToken=7dd5c3163f2cd0cb" /> <asp:ScriptReference Name="Infragistics.Web.UI.GridControls.WebDataGrid.js.igWebDataGrid.js" Assembly="Infragistics35.Web.v8.3, Version=8.3.20083.169, Culture=neutral, PublicKeyToken=7dd5c3163f2cd0cb" /> <asp:ScriptReference Name="Infragistics.Web.UI.GridControls.WebDataGrid.js.igWebDataGridPaging.js" Assembly="Infragistics35.Web.v8.3, Version=8.3.20083.169, Culture=neutral, PublicKeyToken=7dd5c3163f2cd0cb" /> <asp:ScriptReference Name="Infragistics.Web.UI.GridControls.WebDataGrid.js.igWebDataGridActivation.js" Assembly="Infragistics35.Web.v8.3, Version=8.3.20083.169, Culture=neutral, PublicKeyToken=7dd5c3163f2cd0cb" /> <asp:ScriptReference Name="Infragistics.Web.UI.GridControls.WebDataGrid.js.igWebDataGridSorting.js" Assembly="Infragistics35.Web.v8.3, Version=8.3.20083.169, Culture=neutral, PublicKeyToken=7dd5c3163f2cd0cb" />
Go back to your form and remove the ScriptReferenceProfiler contorl, and the references to the ScriptReferenceProfiler you added above. Paste the contents of your clipboard into the ScriptManager tag's CompositeScript subtag as seen below.
<asp:ScriptManager ID="sm" runat="server"> <CompositeScript> <Scripts> <asp:ScriptReference Name="MicrosoftAjax.js" /> <asp:ScriptReference Name="MicrosoftAjaxWebForms.js" /> <asp:ScriptReference Name="Infragistics.Web.UI.Scripts.0_igControlMain.js" Assembly="Infragistics35.Web.v8.3, Version=8.3.20083.169, Culture=neutral, PublicKeyToken=7dd5c3163f2cd0cb" /> <asp:ScriptReference Name="Infragistics.Web.UI.Scripts.2_igCollections.js" Assembly="Infragistics35.Web.v8.3, Version=8.3.20083.169, Culture=neutral, PublicKeyToken=7dd5c3163f2cd0cb" /> <asp:ScriptReference Name="Infragistics.Web.UI.Scripts.3_igUIBehaviors.js" Assembly="Infragistics35.Web.v8.3, Version=8.3.20083.169, Culture=neutral, PublicKeyToken=7dd5c3163f2cd0cb" /> <asp:ScriptReference Name="Infragistics.Web.UI.Scripts.4_igEnums.js" Assembly="Infragistics35.Web.v8.3, Version=8.3.20083.169, Culture=neutral, PublicKeyToken=7dd5c3163f2cd0cb" /> <asp:ScriptReference Name="Infragistics.Web.UI.Scripts.5_igObjects.js" Assembly="Infragistics35.Web.v8.3, Version=8.3.20083.169, Culture=neutral, PublicKeyToken=7dd5c3163f2cd0cb" /> <asp:ScriptReference Name="Infragistics.Web.UI.Scripts.7_igClientStateManager.js" Assembly="Infragistics35.Web.v8.3, Version=8.3.20083.169, Culture=neutral, PublicKeyToken=7dd5c3163f2cd0cb" /> <asp:ScriptReference Name="Infragistics.Web.UI.Scripts.8_igCallback.js" Assembly="Infragistics35.Web.v8.3, Version=8.3.20083.169, Culture=neutral, PublicKeyToken=7dd5c3163f2cd0cb" /> <asp:ScriptReference Name="Infragistics.Web.UI.Scripts.9_igPropertyManagers.js" Assembly="Infragistics35.Web.v8.3, Version=8.3.20083.169, Culture=neutral, PublicKeyToken=7dd5c3163f2cd0cb" /> <asp:ScriptReference Name="Infragistics.Web.UI.GridControls.WebDataGrid.js.igWebDataGridBase.js" Assembly="Infragistics35.Web.v8.3, Version=8.3.20083.169, Culture=neutral, PublicKeyToken=7dd5c3163f2cd0cb" /> <asp:ScriptReference Name="Infragistics.Web.UI.GridControls.WebDataGrid.js.igWebDataGrid.js" Assembly="Infragistics35.Web.v8.3, Version=8.3.20083.169, Culture=neutral, PublicKeyToken=7dd5c3163f2cd0cb" /> <asp:ScriptReference Name="Infragistics.Web.UI.GridControls.WebDataGrid.js.igWebDataGridPaging.js" Assembly="Infragistics35.Web.v8.3, Version=8.3.20083.169, Culture=neutral, PublicKeyToken=7dd5c3163f2cd0cb" /> <asp:ScriptReference Name="Infragistics.Web.UI.GridControls.WebDataGrid.js.igWebDataGridActivation.js" Assembly="Infragistics35.Web.v8.3, Version=8.3.20083.169, Culture=neutral, PublicKeyToken=7dd5c3163f2cd0cb" /> <asp:ScriptReference Name="Infragistics.Web.UI.GridControls.WebDataGrid.js.igWebDataGridSorting.js" Assembly="Infragistics35.Web.v8.3, Version=8.3.20083.169, Culture=neutral, PublicKeyToken=7dd5c3163f2cd0cb" /> </Scripts> </CompositeScript> </asp:ScriptManager>