【半原創】將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就被省略了,我主要是要在微信瀏覽器下使用。

  1 //需要引用別的js的時候,就加上如Env.require("cookie.js"),或Env.require("/common/cookie.js"),是用相對路徑還是絕對路徑就看喜好了。
  2 //Env.require可用在頁面模板中,也可用在js文件中,但一定要保證執行時env.js被顯式引入。
  3 //多次Env.require同一個js(不管用相對還是絕對),只有第一次會加載,所以不會重復。
  4 
  5 //程序最后發行的版本,用於作為緩存鍵的前綴,快速更新緩存
  6 var envLastVer = '2014_11_17_17_03';
  7 
  8 //用於存放通道名稱及通信對象的類,這樣可以通過不同通道名稱來區分不同的通信對象  
  9 function HttpRequestObject() {
 10     this.chunnel = null;
 11     this.instance = null;
 12 }
 13 
 14 //用於獲取的腳本或css文件保存對象
 15 function HttpGetObject() {
 16     this.url = null;        //要下載的文件路徑
 17     this.cache_key = null;  //緩存鍵
 18     this.chunnel = null;    //通道名
 19     this.type = null;       //類型,js或css
 20     this.is_fill = false;   //內容是否被填充
 21     this.is_exec = false;   //內容是否已被執行,防止分幾大塊載入后重復執行
 22 }
 23 
 24 //通信處理類,可以靜態引用其中的方法  
 25 var Request = new function () {
 26 
 27     //通信類的緩存  
 28     this.httpRequestCache = new Array();
 29 
 30     //創建新的通信對象 
 31     this.createInstance = function () {
 32         var instance = null;
 33         if (window.XMLHttpRequest) {
 34             //mozilla  
 35             instance = new XMLHttpRequest();
 36             //有些版本的Mozilla瀏覽器處理服務器返回的未包含XML mime-type頭部信息的內容時會出錯。
 37             //因此,要確保返回的內容包含text/xml信息  
 38             if (instance.overrideMimeType) {
 39                 instance.overrideMimeType = "text/xml";
 40             }
 41         }
 42         else if (window.ActiveXObject) {
 43             //IE  
 44             var MSXML = ['MSXML2.XMLHTTP.5.0', 'Microsoft.XMLHTTP', 'MSXML2.XMLHTTP.4.0', 'MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP'];
 45             for (var i = 0; i < MSXML.length; i++) {
 46                 try {
 47                     instance = new ActiveXObject(MSXML[i]);
 48                     break;
 49                 }
 50                 catch (e) {
 51                 }
 52             }
 53         }
 54         return instance;
 55     }
 56 
 57     /**  
 58     * 獲取一個通信對象  
 59     * 若沒指定通道名稱,則默認通道名為"default"  
 60     * 若緩存中不存在需要的通信類,則創建一個,同時放入通信類緩存中  
 61     * @param _chunnel:通道名稱,若不存在此參數,則默認為"default"  
 62     * @return 一個通信對象,其存放於通信類緩存中  
 63     */
 64     this.getInstance = function (_chunnel) {
 65         var instance = null;
 66         var object = null;
 67         if (_chunnel == undefined)//沒指定通道名稱  
 68         {
 69             _chunnel = "default";
 70         }
 71         var getOne = false;
 72         for (var i = 0; i < this.httpRequestCache; i++) {
 73             object = HttpRequestObject(this.httpRequestCache[i]);
 74             if (object.chunnel == _chunnel) {
 75                 if (object.instance.readyState == 0 || object.instance.readyState == 4) {
 76                     instance = object.instance;
 77                 }
 78                 getOne = true;
 79                 break;
 80             }
 81         }
 82         if (!getOne) //對象不在緩存中,則創建  
 83         {
 84             object = new HttpRequestObject();
 85             object.chunnel = _chunnel;
 86             object.instance = this.createInstance();
 87             this.httpRequestCache.push(object);
 88             instance = object.instance;
 89         }
 90         return instance;
 91     }
 92 
 93     /**  
 94     * 客戶端向服務端發送請求  
 95     * @param _url:請求目的  
 96     * @param _data:要發送的數據  
 97     * @param _processRequest:用於處理返回結果的函數,其定義可以在別的地方,需要有一個參數,即要處理的通信對象  
 98     * @param _chunnel:通道名稱,默認為"default"  
 99     * @param _asynchronous:是否異步處理,默認為true,即異步處理
100     * @param _paraObj:相關的參數對象 
101     */
102     this.send = function (_url, _data, _processRequest, _chunnel, _asynchronous, _paraObj) {
103         if (_url.length == 0 || _url.indexOf("?") == 0) {
104             alert("由於目的為空,請求失敗,請檢查!");
105             return;
106         }
107         if (_chunnel == undefined || _chunnel == "") {
108             _chunnel = "default";
109         }
110         if (_asynchronous == undefined) {
111             _asynchronous = true;
112         }
113         var instance = this.getInstance(_chunnel);
114         if (instance == null) {
115             alert("瀏覽器不支持ajax,請檢查!")
116             return;
117         }
118         if (_asynchronous == true && typeof (_processRequest) == "function") {
119             instance.onreadystatechange = function () {
120                 if (instance.readyState == 4) // 判斷對象狀態  
121                 {
122                     if (instance.status == 200) // 信息已經成功返回,開始處理信息  
123                     {
124                         _processRequest(instance, _paraObj);
125                     }
126                     else {
127                         alert("您所請求的頁面有異常,請檢查!");
128                     }
129                 }
130             }
131         }
132         //_url加一個時刻改變的參數,防止由於被瀏覽器緩存后同樣的請求不向服務器發送請求  
133         if (_url.indexOf("?") != -1) {
134             _url += "&requestTime=" + (new Date()).getTime();
135         }
136         else {
137             _url += "?requestTime=" + (new Date()).getTime();
138         }
139         if (_data.length == 0) {
140             instance.open("GET", _url, _asynchronous);
141             instance.send(null);
142         }
143         else {
144             instance.open("POST", _url, _asynchronous);
145             instance.setRequestHeader("Content-Length", _data.length);
146             instance.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
147             instance.send(_data);
148         }
149         if (_asynchronous == false && typeof (_processRequest) == "function") {
150             _processRequest(instance, _paraObj);
151         }
152     }
153 }
154 
155 var Env = new function () {
156     this.needLoadObject = new Array();
157 
158     //獲取env.js文件所在路徑
159     this.envPath = null;
160     this.getPath = function () {
161         this.envPath = document.location.pathname;
162         this.envPath = this.envPath.substring(0, this.envPath.lastIndexOf("/") + 1);
163         var _scripts = document.getElementsByTagName("script");
164         var _envPath = null;
165         var _scriptSrc = null;
166         for (var i = 0; i < _scripts.length; i++) {
167             _scriptSrc = _scripts[i].getAttribute("src");
168             if (_scriptSrc && _scriptSrc.indexOf("env.js") != -1) {
169                 break;
170             }
171         }
172         if (_scriptSrc != null) {
173             if (_scriptSrc.charAt(0) == '/') {
174                 this.envPath = _scriptSrc.substr(0, _scriptSrc.length - 6);
175             }
176             else {
177                 this.envPath = this.envPath + _scriptSrc.substr(0, _scriptSrc.length - 6);
178             }
179         }
180     }
181     this.getPath();
182 
183     //獲取文件后綴名
184     this.getFileExt = function (fileUrl) {
185         var d = /\.[^\.]+$/.exec(fileUrl);
186         return d.toString().toLowerCase();
187     }
188 
189     //依次放入要載入的文件
190     this.pushNeedLoad = function (url) {
191         var _absUrl = null;
192         if (url.charAt(0) == '/')
193             _absUrl = url;
194         else
195             _absUrl = this.envPath + url;
196 
197         var object = new HttpGetObject();
198         object.url = _absUrl;
199         object.cache_key = envLastVer + _absUrl;    //利用版本號+絕對路徑生成緩存鍵
200         object.chunnel = 'ch' + (this.needLoadObject.length + 1);
201         object.type = this.getFileExt(_absUrl);
202 
203         //嘗試從緩存獲取
204         var cacheContent = localStorage.getItem(object.cache_key);
205         if (cacheContent) { object.is_fill = true; }
206 
207         this.needLoadObject.push(object);
208         return this;
209     }
210 
211     //依次裝載要處理的文件
212     this.batchLoad = function () {
213         for (var i = 0; i < this.needLoadObject.length; i++) {
214             var item = this.needLoadObject[i];
215             var processGet = function (_instance, _paraObj) {
216                 localStorage.setItem(_paraObj.cache_key, _instance.responseText);    //緩存文件
217                 _paraObj.is_fill = true;
218             }
219             if (item.is_fill == false) {
220                 Request.send(item.url, "", processGet, item.chunnel, false, item);  //采用同步方式載入
221             }
222         }
223         return this;
224     }
225 
226     //依次執行要處理的文件
227     this.batchExec = function () {
228         var runCss = function (_css) { document.write('<style type="text/css">' + _css + '</style>'); }
229         var runJs = function (_js) {
230             if (window.execScript)
231                 window.execScript(_js);
232             else
233                 window.eval(_js);
234         }
235         //依次執行,由於js為單線程執行,每執行一個js都會阻塞其它,所以可以保證順序執行
236         for (var i = 0; i < this.needLoadObject.length; i++) {
237             var item = this.needLoadObject[i];
238             if (item.is_exec == false) {
239                 if (item.type == '.js') {
240                     runJs(localStorage.getItem(item.cache_key));
241                     item.is_exec = true;  //標記已執行,下次不會再執行
242                 }
243                 else if (item.type == '.css') {
244                     runCss(localStorage.getItem(item.cache_key));
245                     item.is_exec = true;  //標記已執行,下次不會再執行
246                 }
247             }
248         }
249     }
250 }

下面是調用方法: 

 1         Env.pushNeedLoad("jquery.mobile-1.4.5/jquery.min.js")
 2             .pushNeedLoad("jquery.mobile-1.4.5/jquery.mobile-1.4.5.min.css")
 3             .pushNeedLoad("/plus_in/weixin/procedure/scripts/task.util.js")
 4             .pushNeedLoad("/plus_in/weixin/procedure/scripts/emcp.mobile.js")
 5             .pushNeedLoad("/plus_in/weixin/procedure/scripts/common.index.js")
 6             .pushNeedLoad("jquery.mobile-1.4.5/jquery.mobile-1.4.5.min.js")
 7             .pushNeedLoad("mobiscroll.2.6/css/mobiscroll.custom-2.6.2.min.css")
 8             .pushNeedLoad("mobiscroll.2.6/js/mobiscroll.custom-2.6.2.min.js")
 9             .pushNeedLoad("/plus_in/weixin/procedure/style/base.css")
10             .batchLoad().batchExec();

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM