【半原創】將js和css文件裝入localStorage加速程序執行

首先感謝某某做者寫的文章:http://www.jb51.net/article/12793.htmcss

直接上代碼,注意文件名爲env.jshtml

原理以下:jquery

    一次批量加要加載的文件存入數組,採用Ajax方式異步載入各個文件,而後採用循環方式逐個執行下載下來的Js或者Css文件,若是已經被緩存(localStorage)的則省略下載過程。ajax

    因爲JS採用的是單線程模式運行,在執行某一個js時會阻塞其它併發的js執行,因此會按順序執行各個js。在執行完全部的腳本以後,圖片會被瀏覽器接着加載,因此第一次加載速度略慢,後面就會比較快了。在JQuery Mobile 1.4.5+FireFox/微信瀏覽器下實測效果不錯,IE就被省略了,我主要是要在微信瀏覽器下使用。數組

//須要引用別的js的時候,就加上如Env.require("cookie.js"),或Env.require("/common/cookie.js"),是用相對路徑仍是絕對路徑就看喜愛了。
//Env.require可用在頁面模板中,也可用在js文件中,但必定要保證執行時env.js被顯式引入。
//屢次Env.require同一個js(無論用相對仍是絕對),只有第一次會加載,因此不會重複。

//程序最後發行的版本,用於做爲緩存鍵的前綴,快速更新緩存
var envLastVer = '2014_11_17_17_03';

//用於存放通道名稱及通訊對象的類,這樣能夠經過不一樣通道名稱來區分不一樣的通訊對象  
function HttpRequestObject() {
    this.chunnel = null;
    this.instance = null;
}

//用於獲取的腳本或css文件保存對象
function HttpGetObject() {
    this.url = null;        //要下載的文件路徑
    this.cache_key = null;  //緩存鍵
    this.chunnel = null;    //通道名
    this.type = null;       //類型,js或css
    this.is_fill = false;   //內容是否被填充
    this.is_exec = false;   //內容是否已被執行,防止分幾大塊載入後重復執行
}

//通訊處理類,能夠靜態引用其中的方法  
var Request = new function () {

    //通訊類的緩存  
    this.httpRequestCache = new Array();

    //建立新的通訊對象 
    this.createInstance = function () {
        var instance = null;
        if (window.XMLHttpRequest) {
            //mozilla  
            instance = new XMLHttpRequest();
            //有些版本的Mozilla瀏覽器處理服務器返回的未包含XML mime-type頭部信息的內容時會出錯。
            //所以,要確保返回的內容包含text/xml信息  
            if (instance.overrideMimeType) {
                instance.overrideMimeType = "text/xml";
            }
        }
        else if (window.ActiveXObject) {
            //IE  
            var MSXML = ['MSXML2.XMLHTTP.5.0', 'Microsoft.XMLHTTP', 'MSXML2.XMLHTTP.4.0', 'MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP'];
            for (var i = 0; i < MSXML.length; i++) {
                try {
                    instance = new ActiveXObject(MSXML[i]);
                    break;
                }
                catch (e) {
                }
            }
        }
        return instance;
    }

    /**  
    * 獲取一個通訊對象  
    * 若沒指定通道名稱,則默認通道名爲"default"  
    * 若緩存中不存在須要的通訊類,則建立一個,同時放入通訊類緩存中  
    * @param _chunnel:通道名稱,若不存在此參數,則默認爲"default"  
    * @return 一個通訊對象,其存放於通訊類緩存中  
    */
    this.getInstance = function (_chunnel) {
        var instance = null;
        var object = null;
        if (_chunnel == undefined)//沒指定通道名稱  
        {
            _chunnel = "default";
        }
        var getOne = false;
        for (var i = 0; i < this.httpRequestCache; i++) {
            object = HttpRequestObject(this.httpRequestCache[i]);
            if (object.chunnel == _chunnel) {
                if (object.instance.readyState == 0 || object.instance.readyState == 4) {
                    instance = object.instance;
                }
                getOne = true;
                break;
            }
        }
        if (!getOne) //對象不在緩存中,則建立  
        {
            object = new HttpRequestObject();
            object.chunnel = _chunnel;
            object.instance = this.createInstance();
            this.httpRequestCache.push(object);
            instance = object.instance;
        }
        return instance;
    }

    /**  
    * 客戶端向服務端發送請求  
    * @param _url:請求目的  
    * @param _data:要發送的數據  
    * @param _processRequest:用於處理返回結果的函數,其定義能夠在別的地方,須要有一個參數,即要處理的通訊對象  
    * @param _chunnel:通道名稱,默認爲"default"  
    * @param _asynchronous:是否異步處理,默認爲true,即異步處理
    * @param _paraObj:相關的參數對象 
    */
    this.send = function (_url, _data, _processRequest, _chunnel, _asynchronous, _paraObj) {
        if (_url.length == 0 || _url.indexOf("?") == 0) {
            alert("因爲目的爲空,請求失敗,請檢查!");
            return;
        }
        if (_chunnel == undefined || _chunnel == "") {
            _chunnel = "default";
        }
        if (_asynchronous == undefined) {
            _asynchronous = true;
        }
        var instance = this.getInstance(_chunnel);
        if (instance == null) {
            alert("瀏覽器不支持ajax,請檢查!")
            return;
        }
        if (_asynchronous == true && typeof (_processRequest) == "function") {
            instance.onreadystatechange = function () {
                if (instance.readyState == 4) // 判斷對象狀態  
                {
                    if (instance.status == 200) // 信息已經成功返回,開始處理信息  
                    {
                        _processRequest(instance, _paraObj);
                    }
                    else {
                        alert("您所請求的頁面有異常,請檢查!");
                    }
                }
            }
        }
        //_url加一個時刻改變的參數,防止因爲被瀏覽器緩存後一樣的請求不向服務器發送請求  
        if (_url.indexOf("?") != -1) {
            _url += "&requestTime=" + (new Date()).getTime();
        }
        else {
            _url += "?requestTime=" + (new Date()).getTime();
        }
        if (_data.length == 0) {
            instance.open("GET", _url, _asynchronous);
            instance.send(null);
        }
        else {
            instance.open("POST", _url, _asynchronous);
            instance.setRequestHeader("Content-Length", _data.length);
            instance.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
            instance.send(_data);
        }
        if (_asynchronous == false && typeof (_processRequest) == "function") {
            _processRequest(instance, _paraObj);
        }
    }
}

var Env = new function () {
    this.needLoadObject = new Array();

    //獲取env.js文件所在路徑
    this.envPath = null;
    this.getPath = function () {
        this.envPath = document.location.pathname;
        this.envPath = this.envPath.substring(0, this.envPath.lastIndexOf("/") + 1);
        var _scripts = document.getElementsByTagName("script");
        var _envPath = null;
        var _scriptSrc = null;
        for (var i = 0; i < _scripts.length; i++) {
            _scriptSrc = _scripts[i].getAttribute("src");
            if (_scriptSrc && _scriptSrc.indexOf("env.js") != -1) {
                break;
            }
        }
        if (_scriptSrc != null) {
            if (_scriptSrc.charAt(0) == '/') {
                this.envPath = _scriptSrc.substr(0, _scriptSrc.length - 6);
            }
            else {
                this.envPath = this.envPath + _scriptSrc.substr(0, _scriptSrc.length - 6);
            }
        }
    }
    this.getPath();

    //獲取文件後綴名
    this.getFileExt = function (fileUrl) {
        var d = /\.[^\.]+$/.exec(fileUrl);
        return d.toString().toLowerCase();
    }

    //依次放入要載入的文件
    this.pushNeedLoad = function (url) {
        var _absUrl = null;
        if (url.charAt(0) == '/')
            _absUrl = url;
        else
            _absUrl = this.envPath + url;

        var object = new HttpGetObject();
        object.url = _absUrl;
        object.cache_key = envLastVer + _absUrl;    //利用版本號+絕對路徑生成緩存鍵
        object.chunnel = 'ch' + (this.needLoadObject.length + 1);
        object.type = this.getFileExt(_absUrl);

        //嘗試從緩存獲取
        var cacheContent = localStorage.getItem(object.cache_key);
        if (cacheContent) { object.is_fill = true; }

        this.needLoadObject.push(object);
        return this;
    }

    //依次裝載要處理的文件
    this.batchLoad = function () {
        for (var i = 0; i < this.needLoadObject.length; i++) {
            var item = this.needLoadObject[i];
            var processGet = function (_instance, _paraObj) {
                localStorage.setItem(_paraObj.cache_key, _instance.responseText);    //緩存文件
                _paraObj.is_fill = true;
            }
            if (item.is_fill == false) {
                Request.send(item.url, "", processGet, item.chunnel, false, item);  //採用同步方式載入
            }
        }
        return this;
    }

    //依次執行要處理的文件
    this.batchExec = function () {
        var runCss = function (_css) { document.write('<style type="text/css">' + _css + '</style>'); }
        var runJs = function (_js) {
            if (window.execScript)
                window.execScript(_js);
            else
                window.eval(_js);
        }
        //依次執行,因爲js爲單線程執行,每執行一個js都會阻塞其它,因此能夠保證順序執行
        for (var i = 0; i < this.needLoadObject.length; i++) {
            var item = this.needLoadObject[i];
            if (item.is_exec == false) {
                if (item.type == '.js') {
                    runJs(localStorage.getItem(item.cache_key));
                    item.is_exec = true;  //標記已執行,下次不會再執行
                }
                else if (item.type == '.css') {
                    runCss(localStorage.getItem(item.cache_key));
                    item.is_exec = true;  //標記已執行,下次不會再執行
                }
            }
        }
    }
}

下面是調用方法: 瀏覽器

Env.pushNeedLoad("jquery.mobile-1.4.5/jquery.min.js")
            .pushNeedLoad("jquery.mobile-1.4.5/jquery.mobile-1.4.5.min.css")
            .pushNeedLoad("/plus_in/weixin/procedure/scripts/task.util.js")
            .pushNeedLoad("/plus_in/weixin/procedure/scripts/emcp.mobile.js")
            .pushNeedLoad("/plus_in/weixin/procedure/scripts/common.index.js")
            .pushNeedLoad("jquery.mobile-1.4.5/jquery.mobile-1.4.5.min.js")
            .pushNeedLoad("mobiscroll.2.6/css/mobiscroll.custom-2.6.2.min.css")
            .pushNeedLoad("mobiscroll.2.6/js/mobiscroll.custom-2.6.2.min.js")
            .pushNeedLoad("/plus_in/weixin/procedure/style/base.css")
            .batchLoad().batchExec();

經過火狐F12觀察,發現上面的腳本第一次會被加載,後面將會直接從localstorage中讀取,節省了不少,將js用於微信瀏覽器後,也節省了不少帶寬。不過第一次加載仍是有些慢的,畢竟仍是有那麼多數據。緩存

原文地址:http://www.cnblogs.com/wubin264/p/load_js_css_into_localstorage.html服務器

相關文章
相關標籤/搜索