ASP.Net Site Performance: Improving JavaScript Loading

0
398
10 min read

 

ASP.NET Site Performance Secrets

ASP.NET Site Performance Secrets

Simple and proven techniques to quickly speed up your ASP.NET website

  • Speed up your ASP.NET website by identifying performance bottlenecks that hold back your site’s performance and fixing them
  • Tips and tricks for writing faster code and pinpointing those areas in the code that matter most, thus saving time and energy
  • Drastically reduce page load times
  • Configure and improve compression – the single most important way to improve your site’s performance
  • Written in a simple problem-solving manner – with a practical hands-on approach and just the right amount of theory you need to make sense of it all

 

        Read more about this book      

One approach to improving page performance is to shift functionality from the server to the browser. Instead of calculating a result or validating a form in C# on the server, you use JavaScript code on the browser. A drawback of this approach is that it involves physically moving code from the server to the browser. Because JavaScript is not compiled, it can be quite bulky. This can affect page load times, especially if you use large JavaScript libraries. You’re effectively trading off increased page load times against faster response times after the page has loaded.

In this article by Matt Perdeck, author of ASP.NET Site Performance Secret, you’ll see how to reduce the impact on page load times by the need to load JavaScript files. It shows:

  • How JavaScript files can block rendering of the page while they are being loaded and executed
  • How to load JavaScript in parallel with other resources
  • How to load JavaScript more quickly

(For more resources on ASP.Net, see here.)

Problem: JavaScript loading blocks page rendering

JavaScript files are static files, just as images and CSS files. However, unlike images, when a JavaScript file is loaded or executed using a <script> tag, rendering of the page is suspended.

This makes sense, because the page may contain script blocks after the <script> tag that are dependent on the JavaScript file. If loading of a JavaScript file didn’t block page rendering, the other blocks could be executed before the file had loaded, leading to JavaScript errors.

Confirming with a test site

You can confirm that loading a JavaScript file blocks rendering of the page by running the website in the folder JavaScriptBlocksRendering in the downloaded code bundle. This site consists of a single page that loads a single script, script1.js. It also has a single image, chemistry.png, and a stylesheet style1.css. It uses an HTTP module that suspends the working thread for five seconds when a JavaScript file is loaded. Images and CSS files are delayed by about two seconds. When you load the page, you’ll see that the page content appears after only about five seconds. Then after two seconds, the image appears, unless you use Firefox, which often loads images in parallel with the JavaScript.

If you make a Waterfall chart, you can see how the image and stylesheet are loaded after the JavaScript file, instead of in parallel:

ASP.NET Site Performance Secret

To get the delays, run the test site on IIS 7 in integrated pipeline mode. Do not use the Cassini web server built into Visual Studio.

If you find that there is no delay, clear the browser cache. If that doesn’t work either, the files may be in kernel cache on the server—remove them by restarting IIS using Internet Information Services (IIS) Manager. To open IIS manager, click on Start | Control Panel, type “admin” in the search box, click on Administrative Tools, and then double-click on Internet Information Services (IIS) Manager.

Integrated/Classic Pipeline Mode
As in IIS 6, every website runs as part of an application pool in IIS 7. Each IIS 7 application pool can be switched between Integrated Pipeline Mode (the default) and Classic Pipeline Mode. In Integrated Pipeline Mode, the ASP.NET runtime is integrated with the core web server, so that the server can be managed for example, via web.config elements. In Classic Pipeline Mode, IIS 7 functions more like IIS 6, where ASP.NET runs within an ISAPI extension.

Approaches to reduce the impact on load times

Although it makes sense to suspend rendering the page while a <script> tag loads or executes JavaScript, it would still be good to minimize the time visitors have to wait for the page to appear, especially if there is a lot of JavaScript to load. Here are a few ways to do that:

  • Start loading JavaScript after other components have started loading, such as images and CSS files. That way, the other components load in parallel with the JavaScript instead of after the JavaScript, and so are available sooner when page rendering resumes.
  • Load JavaScript more quickly. Page rendering is still blocked, but for less time.
  • Load JavaScript on demand. Only load the JavaScript upfront that you need to render the page. Load the JavaScript that handles button clicks, and so on, when you need it.
  • Use specific techniques to prevent JavaScript loading from blocking rendering. This includes loading the JavaScript after the page has rendered, or in parallel with page rendering.

These approaches can be combined or used on their own for the best tradeoff between development time and performance. Let’s go through each approach.

Approach: Start loading after other components

This approach aims to render the page sooner by loading CSS stylesheets and images in parallel with the JavaScript rather than after the JavaScript. That way, when the JavaScript has finished loading, the CSS and images will have finished loading too and will be ready to use; or at least it will take less time for them to finish loading after the JavaScript has loaded.

To load the CSS stylesheets and images in parallel with the JavaScript, you would start loading them before you start loading the JavaScript. In the case of CSS stylesheets that is easy—simply place their <link> tags before the <script> tags:

<link rel="Stylesheet" type="text/css" href="css/style1.css" />
<script type="text/javascript" src="js/script1.js"></script>

Starting the loading of images is slightly trickier because images are normally loaded when the page body is evaluated, not as a part of the page head.

In the test page you just saw with the image chemistry.png, you can use a bit of simple JavaScript to get the browser to start loading the image before it starts loading the JavaScript file. This is referred to as “image preloading” (page PreLoadWithJavaScript.aspx in the folder PreLoadImages in the downloaded code bundle):

<script type="text/javascript">
var img1 = new Image(); img1.src = "images/chemistry.png";
</script>
<link rel="Stylesheet" type="text/css" href="css/style1.css" />
<script type="text/javascript" src="js/script1.js"></script>

Run the page now and you’ll get the following Waterfall chart:

ASP.NET Site Performance Secret

When the page is rendered after the JavaScript has loaded, the image and CSS files have already been loaded; so the image shows up right away.

A second option is to use invisible image tags at the start of the page body that preload the images. You can make the image tags invisible by using the style display:none. You would have to move the <script> tags from the page head to the page body after the invisible image tags, as shown (page PreLoadWithCss.aspx in folder PreLoadImages in the downloaded code bundle):

<body>
<div style="display:none">
<img src="images/chemistry.png" />
</div>
<script type="text/javascript" src="js/script1.js"></script>

Although the examples we’ve seen so far preload only one image, chemistry.png, you could easily preload multiple images. When you do, it makes sense to preload the most important images first, so that they are most likely to appear right away when the page renders. The browser loads components, such as images, in the order in which they appear in the HTML, so you’d wind up with something similar to the following code:

<script type="text/javascript">
var img1 = new Image(); img1.src = "images/important.png";
var img1 = new Image(); img2.src = "images/notsoimportant.png";
var img1 = new Image(); img3.src = "images/unimportant.png";
</script>

Approach: Loading JavaScript more quickly

The second approach is to simply spend less time loading the same JavaScript, so that visitors spend less time waiting for the page to render. There are a number of ways to achieve just that:

  • Techniques used with images, such as caching and parallel download
  • Free Content Delivery Networks
  • GZIP compression
  • Minification
  • Combining or breaking up JavaScript files
  • Removing unused code

Techniques used with images

JavaScript files are static files, just like images and CSS files. This means that many techniques that apply to images apply to JavaScript files as well, including the use of cookie-free domains, caching, and boosting parallel loading.

Free Content Delivery Networks

Serving static files from a Content Delivery Network (CDN) can greatly reduce download times, by serving the files from a server that is close to the visitor. A CDN also saves you bandwidth because the files are no longer served from your own server.

A number of companies now serve popular JavaScript libraries from their CDNs for free. Here are their details:

In ASP.NET 4.0 and later, you can get the ScriptManager control to load the ASP. NET AJAX script files from the Microsoft AJAX CDN instead of your web server, by setting the EnableCdn property to true:

<asp:ScriptManager ID="ScriptManager1"
EnableCdn="true" runat="server" />

One issue with loading libraries from a CDN is that it creates another point of failure—if the CDN goes down, your site is crippled.

GZIP compression

IIS has the ability to compress content sent to the browser, including JavaScript and CSS files.

Compression can make a dramatic difference to a JavaScript file as it goes over the wire from the server to the browser. Take for example the production version of the jQuery library:

 

Uncompressed Compressed
jQuery library 78 KB 26 KB

 

Compression for static files is enabled by default in IIS 7. This immediately benefits CSS files. It should also immediately benefit JavaScript files, but it doesn’t because of a quirk in the default configuration of IIS 7.

Not all static files benefit from compression; for example JPEG, PNG, and GIF files are already inherently compressed because of their format. To cater to this, the IIS 7 configuration file applicationHost.config contains a list of mime types that get compressed when static compression is enabled:

<staticTypes>
<add mimeType="text/*" enabled="true" />
<add mimeType="message/*" enabled="true" />
<add mimeType="application/javascript" enabled="true" />
<add mimeType="*/*" enabled="false" />
</staticTypes>

To allow IIS to figure out what mime type a particular file has, applicationHost.config also contains default mappings from file extensions to mime types, including this one:

<staticContent lockAttributes="isDocFooterFileName">
...
<mimeMap fileExtension=".js"
mimeType="application/x-javascript" />
...
</staticContent>

If you look closely, you’ll see that the .js extension is mapped by default to a mime type that isn’t in the list of mime types to be compressed when static file compression is enabled.

The easiest way to solve this is to modify your site’s web.config, so that it maps the extension .js to mime type text/javascript. This matches text/* in the list of mime types to be compressed. So, IIS 7 will now compress JavaScript files with the extension .js (folder Minify in the downloaded code bundle):

<system.webServer>
<staticContent>
<remove fileExtension=".js" />
<mimeMap fileExtension=".js" mimeType="text/javascript" />
</staticContent>
</system.webServer>

Keep in mind that IIS 7 only applies static compression to files that are “frequently” requested. This means that the first time you request a file, it won’t be compressed! Refresh the page a couple of times and compression will kick in.

LEAVE A REPLY

Please enter your comment!
Please enter your name here