Click here to Skip to main content
Click here to Skip to main content
Articles » Web Development » ASP.NET » Howto » Downloads
 
Add your own
alternative version
Go to top

Fast ASP.NET Web page loading by downloading multiple JavaScripts after visible content and in batch

, 3 Aug 2008
Download all external scripts on your Web page after the visible content is loaded for faster perceived speed and donwload multiple JavaScript in batch for better actual speed
FastLoad_src.zip
FastLoad_src
App_Code
App_Data
Global.asax
<%@ WebHandler Language="C#" Class="Scripts" %>

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Web;
using System.Net;

using Dropthings.Web.Util;

public class Scripts : IHttpHandler {
    
    public void ProcessRequest (HttpContext context) {

        
        string queryString = HttpUtility.UrlDecode(context.Request.QueryString.ToString());

        string[] urlSplit = queryString.Split('&');

        string setInfo = urlSplit[0];
        string urlPrefix = urlSplit[1];

        string[] tokens = setInfo.Split('=');
        string setName = tokens[0];
        string[] urlMaps = tokens[1].Split(',');

        byte[] encodedBytes;

        if (context.Cache[setInfo] == null)
        {
            // Find the set
            UrlMapSet set = CombineScripts.LoadSets().Find(
                new Predicate<UrlMapSet>(delegate(UrlMapSet match)
                    {
                        return match.Name == setName;
                    }));

            // Find the URLs requested to be rendered            
            List<UrlMap> maps = string.IsNullOrEmpty(tokens[1]) ? set.Urls 
                : set.Urls.FindAll(new Predicate<UrlMap>(delegate(UrlMap map)
                    {
                        return Array.BinarySearch<string>(urlMaps, map.Name) >= 0;
                    }));

            string urlScheme = context.Request.Url.GetComponents(UriComponents.SchemeAndServer, UriFormat.Unescaped);

            StringBuilder buffer = new StringBuilder();
            foreach (UrlMap map in maps)
            {
                /*
                 * Urls can be in one of the following formats:
                 * a) Relative url to the page
                 * b) Relative url starting with application path e.g. /Dropthings/....
                 * c) Absolute url with http:// prefix
                 */

                string fullUrl = map.Url;
                if (map.Url.StartsWith("http://")) fullUrl = map.Url;
                else if (map.Url.StartsWith(context.Request.ApplicationPath)) fullUrl = urlScheme + map.Url;
                else fullUrl = urlScheme + urlPrefix + map.Url;

                string mapUrlForJS = HttpUtility.HtmlDecode(map.Url).Replace("'", "\'");
                HttpWebRequest request = this.CreateHttpWebRequest(fullUrl);
                try
                {
                    using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
                    {
                        if (response.StatusCode == HttpStatusCode.OK)
                        {
                            using (StreamReader reader = new StreamReader(response.GetResponseStream()))
                            {
                                string responseContent = reader.ReadToEnd();
                                buffer.Append(responseContent);
                                buffer.Append(Environment.NewLine);
                                buffer.Append(@"
                            if(typeof(Sys)!=='undefined') Array.add(Sys._ScriptLoader._getLoadedScripts(), '" + mapUrlForJS + @"'); 
                            if( !window._combinedScripts ) { window._combinedScripts = []; } 
                            window._combinedScripts.push('" + mapUrlForJS + @"');");
                                buffer.Append(Environment.NewLine);
                            }
                        }
                        else
                        {
                            buffer.Append("alert(\"Cannot load script from:" + mapUrlForJS + ". Please correct mapping for '" + map.Name + "' in App_Data\\\\FileSets.xml\");");
                            buffer.Append(Environment.NewLine);
                        }
                    }
                }
                catch (Exception x)
                {
                    buffer.Append("alert(\"Cannot load script from:" + mapUrlForJS + ". Please correct mapping for '" + map.Name + "' in App_Data\\\\FileSets.xml\");");
                    buffer.Append(Environment.NewLine);
                }
            }

            buffer.Append(@"
                if(typeof(Sys)!=='undefined')             
                {                
                    if(typeof(Sys._ScriptLoader) !== 'undefined')
                    {                                    
                        Sys._ScriptLoader.isScriptLoaded = function Sys$_ScriptLoader$isScriptLoaded(scriptSrc) 
                        {                                                    
                            var dummyScript = document.createElement('script');
                            dummyScript.src = scriptSrc;
                            var result = Array.contains(Sys._ScriptLoader._getLoadedScripts(), scriptSrc);
                            if( result === true ) return true;
                            result = Array.contains( window._combinedScripts, scriptSrc );
                            if( result === true ) return true;                            
                            var scriptTags = document.getElementsByTagName('script');
                            for(var i = 0; i < scriptTags.length; i ++ ) if( scriptTags[i].src == dummyScript.src ) return true;
                            return false;
                        }
                    }                    
                }");

            string responseString = buffer.ToString();
            encodedBytes = context.Request.ContentEncoding.GetBytes(responseString);
            //context.Cache.Add(setInfo, encodedBytes, null, DateTime.MaxValue,
            //    TimeSpan.FromDays(1), System.Web.Caching.CacheItemPriority.Normal, null);
        }
        else
        {
            encodedBytes = context.Cache[setInfo] as byte[];
        }
        
        context.Response.ContentType = "text/javascript";
        context.Response.ContentEncoding = context.Request.ContentEncoding;
        context.Response.Cache.SetMaxAge(TimeSpan.FromDays(30));
        context.Response.Cache.SetExpires(DateTime.Now.AddDays(30));
        context.Response.Cache.SetCacheability(HttpCacheability.Private);
        context.Response.AppendHeader("Content-Length", encodedBytes.Length.ToString());
        
        context.Response.OutputStream.Write(encodedBytes, 0, encodedBytes.Length);
        context.Response.Flush();
    }
 
    public bool IsReusable {
        get {
            return false;
        }
    }

    private HttpWebRequest CreateHttpWebRequest(string url)
    {
        HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
        request.Headers.Add("Accept-Encoding", "gzip");
        request.AutomaticDecompression = DecompressionMethods.GZip;
        request.MaximumAutomaticRedirections = 2;
        request.MaximumResponseHeadersLength = 4 * 1024;
        request.ReadWriteTimeout = 1 * 1000;
        request.Timeout = 5 * 1000;

        return request;
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

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

Share

About the Author


| Advertise | Privacy | Mobile
Web01 | 2.8.140916.1 | Last Updated 3 Aug 2008
Article Copyright 2008 by Omar Al Zabir
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid