zoukankan      html  css  js  c++  java
  • 【半原创】将js和css文件装入localStorage加速程序执行

    首先感谢某某作者写的文章:http://www.jb51.net/article/12793.htm

    直接上代码,注意文件名为env.js

    原理如下:

        一次批量加要加载的文件存入数组,采用Ajax方式异步载入各个文件,然后采用循环方式逐个执行下载下来的Js或者Css文件,如果已经被缓存(localStorage)的则省略下载过程。

        由于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

  • 相关阅读:
    poj 2411 Mondriaan's Dream 骨牌铺放 状压dp
    zoj 3471 Most Powerful (有向图)最大生成树 状压dp
    poj 2280 Islands and Bridges 哈密尔顿路 状压dp
    hdu 3001 Travelling 经过所有点(最多两次)的最短路径 三进制状压dp
    poj 3311 Hie with the Pie 经过所有点(可重)的最短路径 floyd + 状压dp
    poj 1185 炮兵阵地 状压dp
    poj 3254 Corn Fields 状压dp入门
    loj 6278 6279 数列分块入门 2 3
    VIM记事——大小写转换
    DKIM支持样本上传做检测的网站
  • 原文地址:https://www.cnblogs.com/7qin/p/9702624.html
Copyright © 2011-2022 走看看