Click here to Skip to main content
15,886,199 members
Articles / Web Development / ASP.NET

Website Performance with ASP.NET - Part 3 - Make Fewer HTTP Requests

Rate me:
Please Sign up or sign in to vote.
5.00/5 (1 vote)
23 Mar 2013CPOL5 min read 13.5K   8  
One of the keys to improving page load times is to reduce the number of requests. This post shows how that can be achieved in ASP.NET websites.

The previous post was all about improving server-side code. The time your server needs to deliver the HTML is important as it delays loading all other resources. It is, however, usually not the crucial part of the page load time. Because 80-90% of the end-user response time is spent on the frontend, there is much more potential for improvements.

One of the key measures for improving page load times is reducing the number of requests because every request comes with an overhead, impacting the total load time.

Combining Requests

One way to reduce the number of requests is to combine multiple resources into one request. There are three types of files which are prime candidates for combining. (Small) images, CSS files and JavaScript files. Reducing the number of referenced js files is especially important as many browser do not, or only limited support parallel downloading of js files.

ASP.NET already contains a component for bundling JavaScript and CSS files (System.Web.Optimization) which is by default included in the web project template. However, this was only "recently" introduced with ASP.NET MVC 4 and there are many more components available. The following table contains some of the most popular ones.

Tool Mode Configuration Sprites Minification Debug Support
Web Essentials build-time xml no AjaxMin manually
Chirpy build-time xml no multiple manually
combres run-time xml no multiple yes
cassette run-time code no AjaxMin yes
RequestReduce run-time auto yes AjaxMin manually
System.Web.Optimization run-time code no own yes

If you have the time, take a look at several different solutions as many of them provide additional features like support for coffee-/typescript, SASS/LESS or HTML templates. All of them support bundling and minification but there are nevertheless notable differences even when just considering these features. When deciding which one you want to use, you should at first decide whether you want run-time or build-time support.

When using "run-time mode", files are combined at run-time, e.g. using a HttpHandler. In "build-time mode", the files are combined during the build or when one of the source files changes. Combining once during development is more efficient as the combined files can then be delivered as static files directly by the IIS or can be uploaded to a CDN. For high volume websites, this is probably the way to go. Currently, the visual plug in Web Essentials is my favorite tool in this area.

If you don't require this strong focus on performance and scalability, I would suggest starting with one of the components working at run-time. They are not as efficient but are usually more flexible and have better debugging support (= no bundling/minification during development). Of course, the default choice will be the bundling & minification component provided by ASP.NET, but if you require additional features, take a look at combres or cassette. Combres supports not only the Microsoft Ajax Minifier but also other minification algorithms like YUI compressor or google closure compiler. The downside of having all these different options are the dependencies on the minification libraries. Updates often cause version conflicts or incompatibilities, so you should well consider if you really need additional minification algorithms.

If you want to optimize an existing site, RequestReduce might be the right choice for you. It was especially developed for integration with existing sites, requiring minimal effort. It is also interesting if you need dynamic generation of sprite images.

Example

The ASP.NET MVC 4 project template contains a configuration for the System.Web.Optimzation run-time bundeling and minification feature (in "App_Start\BundleConfig.cs"). To combine jquery and all jquery plugins, you just need to define a script bundle:

JavaScript
public static void RegisterBundles(BundleCollection bundles)
{
	bundles.Add(
		new ScriptBundle("~/bundles/jquery").Include(
			"~/Scripts/jquery-1.8.2.js",
			"~/Scripts/jquery-ui-1.9.2.js",
			"~/Scripts/jquery.unobtrusive-ajax.js",
			"~/Scripts/jquery.validate.js",
			"~/Scripts/jquery.validate.unobtrusive.js"));
}

and reference it in your layout:

@Scripts.Render("~/bundles/jquery")

To achieve the same using the Web Essentials, select the script files in the solution explorer and click "Web Essentials" -> "Create JavaScript bundle file". After entering the name of the bundle, a configuration file will be created containing a list of files which be should be combined, and whether a minified version should generated.

XML
<bundle minify="true" runOnBuild="true">
  <!--The order of the <file> elements determines the order of them when bundled.-->
  <file>/Scripts/jquery-1.8.2.js</file>
  <file>/Scripts/jquery-ui-1.9.2.js</file>
  <file>/Scripts/jquery.unobtrusive-ajax.js</file>
  <file>/Scripts/jquery.validate.js</file>
  <file>/Scripts/jquery.validate.unobtrusive.js</file>
</bundle>

The corresponding files "{bundleName}.js" and "{bundleName}.min.js" are not only generated on build, but also when one of the source files changes. The bundles are created as simple js files which can be delivered as static content and referenced like any other js file.

Lazy Loading

Another way to reduce the number of HTTP requests (at page load) is to delay loading resources which are not immediately required. This usually applies best to images. Imagine a photo gallery containing hundreds of photos or an online shop with lots of widgets containing mainly not (yet) visible images. Lazy loading of images is usually done by setting the src attribute of the image to a placeholder image and storing the real image URL in a data attribute. Only when the image is in the viewport, the src attribute is updated with the real image URL. You can check out the difference on the example pages without lazy loading and with lazy loading. If you don't want to write the lazy loading JavaScript yourself, you can use a library like the Lazy Load plug in for jQuery, which is also used in the demo project.

If you want to try it yourself , you can use this small snippet. If you don't have an insanely high resolution, the second image should not be loaded until you scroll down. For two images, you obviously don't gain anything but it works the same for a page with a dozen or hundreds of images. When using the lazy load plug in for a production website, check out the options, which allow you to tweak its behavior (e.g. define custom triggers, adjust sensitivity or add effects).

XML
<img data-original="http://baconmockup.com/640/480" 
  src="http://placehold.it/640x480" width="640" height="480" />

<div style="height:2000px">I'm just a big placeholder</div>

<img data-original="http://placesheen.com/640/480" 
  src="http://placehold.it/640x480" width="640" height="480" />

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="//cdn.jsdelivr.net/jquery.lazyload/1.8.4/jquery.lazyload.js"></script>
<script>
	$(function () {
		$("img").lazyload();
	})
</script>

These are two of the low hanging fruits and should enable you to reduce the number of HTTP requests without investing a lot of work.

Next time, we will take a closer look at cache control headers.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Germany Germany
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
-- There are no messages in this forum --