extjs中js资源缓存策略
生活随笔
收集整理的這篇文章主要介紹了
extjs中js资源缓存策略
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
http的緩存協(xié)商
瀏覽器對靜態(tài)文件的緩存主要是通過cache-control來控制的,cache-control可以設置no-cache,max-age以及must-revalidate等來設置緩存策略。如果max-age> 0則會在max-age的時間內不訪問服務器,用本地緩存的靜態(tài)文件代替。 如果max-age<=0則會每次都詢問服務器,資源文件是否有修改,有則200,無則304。這相當于f5操作。 no-cache表示不理會緩存協(xié)商,全部重新加載。這相當于是ctrl+f5操作。 must-revalidate表示必須遵循策略規(guī)則。因為瀏覽器有時候會提取過期的緩存,設置了這個策略后,瀏覽器會嚴格遵循客戶設置的策略。
服務器在首次應答客戶的request時,會返回last-modified和etag給瀏覽器,瀏覽器將cache住這些信息,下一次request服務器時就會在header里帶上if-modified-since和if-non-match信息,這兩個分別對應last-modified和etag。服務器會提取對應資源的modified時間和etag來做對比,如果有改變則返回200并且response last-modified和etag給客戶端,沒變則返回304不需要改變。
目前tomcat已經(jīng)支持etag, tomcat是根據(jù)文件的contentLength和lastModified混合編碼生成串兒。因為last-modified因為只支持到秒級,所以對于秒內頻繁修改的靜態(tài)資源效率會比較低下,etag則很好的避免了這一點。
對靜態(tài)資源的處理策略
一般對于靜態(tài)資源,服務器端會通過過濾機制,自動為響應的header里添加max-age信息,這樣瀏覽器就會在本地cache住這些資源。我們最近的一個項目,前臺使用extjs,使用extjs帶來的成本就是所有的頁面幾乎都是js頁面了。因為靜態(tài)js的文件量大,且我們系統(tǒng)的運營地點非洲網(wǎng)絡條件不太好,帶寬資源比較寶貴,不能承受頻繁的靜態(tài)資源請求(這里需要提一點,即使是web服務器最終響應不需要更改的304請求,對系統(tǒng)也是一次帶寬開銷,我們也想盡力避免),于是我們想通過cache-contro將js文件cache在本地。但是這就帶來一個問題,對于緊急發(fā)布的一些前臺界面,因為超時機制會無法及時在系統(tǒng)層面體現(xiàn)。
所以我們必須實現(xiàn)一種機制,在發(fā)布了新的js后,對應的引用該js的地方都要能自動刷新。所以最簡單的方法就是每次編譯完后生成一個版本號,然后對每個引用js的url都添加上版本號就ok。這樣就可以保證在一次發(fā)布周期內始終只有一個js版本。
Extjs的動態(tài)加載策略
Extjs實現(xiàn)了一套動態(tài)加載策略,可以通過js語言的方式去直接引入一個資源(Ext.require),這和我們平時使用的靜態(tài)引用(<script src=" xxx")是完全不同的。所以決定研究一下extjs的動態(tài)加載機制。目前網(wǎng)上有開源的extjs4的源碼,在動態(tài)load script時,會讀取config配置信息,config可以通過loader.setConfig來配置。config里有兩個參數(shù)需要注意,一個是disableCachingParam還有一個是disableCaching,后者代表是否需要為每一個請求都聲稱一個版本信息,前者是版本信息的參數(shù)名,默認是_dc.
loadScriptFile: function(url, onLoad, onError, scope, synchronous) { ? ? ? ? ? ? if (isFileLoaded[url]) { ? ? ? ? ? ? ? ? return Loader; ? ? ? ? ? ? }
? ? ? ? ? ? var config = Loader.getConfig(), ? ? ? ? ? ? ? ? noCacheUrl = url + (config.disableCaching ? ('?' + config.disableCachingParam + '=' + Ext.Date.now()) : ''), ? ? ? ? ? ? ? ? isCrossOriginRestricted = false, ? ? ? ? ? ?? ? ? ? ? ? ? if (!synchronous) { ? ? ? ? ? ? ? ? onScriptError = function() { ? ? ? ? ? ? ? ? ? ? //<debug error> ? ? ? ? ? ? ? ? ? ? onError.call(scope, "Failed loading '" + url + "', please verify that the file exists", synchronous); ? ? ? ? ? ? ? ? ? ? //</debug> ? ? ? ? ? ? ? ? };
? ? ? ? ? ? ? ? scriptElements[url] = Loader.injectScriptElement(noCacheUrl, onLoad, onScriptError, scope); ? ? ? ? ? ? } else { ? ? ? ? ? ? ? ? /** ? ? ? ? ? ? ? ? * 組裝xmlhttprequest對象,根據(jù)瀏覽器支持情況初始化activexobject或者xmlhttprquest ? ? ? ? ? ? ? ? */ ? ? ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? ? ? xhr.open('GET', noCacheUrl, false); ? ? ? ? ? ? ? ? ? ? xhr.send(null); ? ? ? ? ? ? ? ? } catch (e) { ? ? ? ? ? ? ? ? ? ? isCrossOriginRestricted = true; ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? /** * 偽代碼,跨域失敗,執(zhí)行onerror回調函數(shù) */
? ? ? ? ? ? ? ? else if ((status >= 200 && status < 300) || (status === 304) ? ? ? ? ? ? ? ? ? ? //<if isNonBrowser> ? ? ? ? ? ? ? ? ? ? || isPhantomJS ? ? ? ? ? ? ? ? ? ? //</if> ? ? ? ? ? ? ? ? ) { ? ? ? ? ? ? ? ? ? ? //調用成功, 記錄調試信息 ? ? ? ? ? ?Ext.globalEval(xhr.responseText + debugSourceURL); ? ? ? ? ? ? ? ? ? ? onLoad.call(scope); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? else { ? ? ? ? ? ? ? ? ? ?/** ? ?* 偽代碼,執(zhí)行onerror回調函數(shù) ? ?*/ ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? // Prevent potential IE memory leak ? ? ? ? ? ? ? ? xhr = null; ? ? ? ? ? ? } ? ? ? ? }
代碼很好理解,同步時直接加載,并且通過eval方法直接執(zhí)行響應的js文件(responseText),異步時則通過injectScriptElement加載,同步還是異步可以通過loader里的syncModeEnabled來設置,默認是false。
注意下這個方法里的noCacheUrl,根據(jù)disableCaching決定要不要為url加上版本信息,緩存無效時會默認以當前時間為版本號。
injectScriptElement: function(url, onLoad, onError, scope, charset) { ? ? ? ? ? ? var script = document.createElement('script'), ? ? ? ? ? ? ? ? dispatched = false, ? ? ? ? ? ? ? ? /** * 設置onload和onerror的回調函數(shù),主要是通過dispatched參數(shù)做冪等性校驗 ? ? ? ? ? ? ? ? * 為了兼容ie,script需要支持onreadystatechange事件,這個事件會又多個狀態(tài),所以需要做冪等校驗 */
? ? ? ? ? ? script.type = 'text/javascript'; ? ? ? ? ? ? script.onerror = onErrorFn; ? ? ? ? ? ? charset = charset || config.scriptCharset; ? ? ? ? ? ? if (charset) { ? ? ? ? ? ? ? ? script.charset = charset; ? ? ? ? ? ? }
? ? ? ? ? ? //兼容ie ? ? ? ? ? ? if ('addEventListener' in script ) { ? ? ? ? ? ? ? ? script.onload = onLoadFn; ? ? ? ? ? ? } else if ('readyState' in script) { ? // for <IE9 Compatability ? ? ? ? ? ? ? ? script.onreadystatechange = function() { ? ? ? ? ? ? ? ? ? ? if ( this.readyState == 'loaded' || this.readyState == 'complete' ) { ? ? ? ? ? ? ? ? ? ? ? ? onLoadFn(); ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? }; ? ? ? ? ? ? } else { ? ? ? ? ? ? ? ? ?script.onload = onLoadFn; ? ? ? ? ? ? }
? ? ? ? ? ? script.src = url; ? ? ? ? ? ? (Loader.documentHead || document.getElementsByTagName('head')[0]).appendChild(script);
? ? ? ? ? ? return script; ? ? ? ? } 該方法主要是創(chuàng)建了一個script的元素,url是前面方法生成的。
因為我們需要的是基于發(fā)布版本信息的緩存,所以只需要將noCacheUrl的版本信息由當前時間戳改成編譯產(chǎn)生的版本信息即可。
最后,注意,因為extjs6做了比較大的重構,url生成挪到了ext.data.proxy.server里的buildUrl里: url = Ext.urlAppend(url, Ext.String.format("{0}={1}", me.getCacheString(), Ext.Date.now())),搜索這一行即可。
總結
以上是生活随笔為你收集整理的extjs中js资源缓存策略的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [ZigBee] 7、ZigBee之UA
- 下一篇: mybatis源码解析(五) --- t