【轉】基於localStorage的資源離線和更新技術
ServiceWorker的資源離線與更新
ServiceWorker是替代Application Cache的機制,目前為止其兼容性很差。
localStorage資源離線緩存與更新
基本思路:將JavaScript、CSS資源文件甚至是接口返回的數據資源緩存到瀏覽器的localStorage中,下次打開頁面時不進行JavaScript、CSS資源的請求,而是直接通過localStorage讀取內容,然後插入到頁面中解析執行。
HTML
<div id="versionStore" data-version="2"></div>
JS
/** * localStorage方式實現增量更新 */ let localStorage = window.localStorage, oldVersion = localStorage.getItem(‘version‘) || 0, // version記錄localStorage中存的版本 newVersion = +document.querySelector(‘#versionStore‘).getAttribute(‘data-version‘); // 當前最新版本 let content = null; if(newVersion > oldVersion) { // 內容有更新或第一次加載 const xhr = new XMLHttpRequest(); xhr.onreadystatechange = function(event){ if (xhr.readyState == 4){ if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){ content = xhr.responseText; updateScript(content); // 更新腳本 localStorage.setItem(‘version‘, newVersion); // 更新本地版本 localStorage.setItem(‘a.js‘, content); // 更新本地內容 } } }; xhr.open("get", "index.js", true); xhr.send(null); } else { // 無內容更新 content = localStorage.getItem(‘a.js‘); // 直接獲取本地內容 updateScript(content) } /** * 更新頁面腳本 * @param content 腳本內容 */ function updateScript(content) { let script = document.createElement(‘script‘); script.innerHTML = content; document.body.appendChild(script); script = null; }
頁面腳本通過獲取頁面上的“最新版本號”和本地localStorage保存的“舊版本號”進行對比。如果本地沒有版本號或者版本號較舊,則加載最新版本的靜態資源文件到頁面上,同時更新本地原有的localStorage緩存的內容和版本號;否則直接讀取localStorage的靜態資源內容到頁面中解析執行。
缺點:(1)localStorage的大小限制,同域下一般是5MB;(2)用戶手動清空localStorage會使離線資源失效;(3)讀取localStorage的速度比較慢,尤其是移動端。
基於增量文件的更新方式
如果一個文件中只修改了少量字符,上述方式會導致整個資源文件的更新。為了節省流量我們需要增量更新。假設我們已有1.1,1.2,1.3三個版本發布,現在需要進行1.4的發布上線。為了滿足增量更新,我們需要根據前面的三個版本文件內容與最新版本內容進行對比分析,分別生成三個不同版本的增量文件1.1-1.4.js,1.2-1.4.js,1.3-1.4.js,同時保留1.4版本的全量文件。
// 實現方式跟上述類似,只需修改請求地址 xhr.open("get", `${oldVersion}-${newVersion}.js`, true);
基於文件代碼分塊的增量更新機制
根據大小確定分割字符數(比如10個字符),文件字符串由幾個字符串塊連接組成chunk1-chunk2-chunk3-chunk4,此時需要在chunk1和chunk2之間添加data1,chunk3內容修改為chunk5,chunk4的塊被刪除。
[1, data1, 2, chunk5, -4]
1表示原來chunk1的內容不變,data1表示插入的新內容;-4表示刪除chunk4的文件塊;
let a = 1, b = 1; console.log(a, b); // 修改為 let a = 2, b = 2; console.log(a + b);
基於編輯距離的增量更新機制
上面方式節約資源的量取決於塊的大小和內容變化的塊序號分布。根據編輯距離算法增量更新的方式可以真正做到字符級別的更新。它指的是從一個字符串變換到另一個字符串所需要的最少變化操作步驟。如果能計算獲取兩個文件對比變化時每個字符的操作步驟,就可以將操作步驟作為增量文件下載,然後在瀏覽器端進行代碼的運算更新了。不過這種情況對於少量的字符更新很有用,如果一次更新的內容很多,生成的增量文件很可能比源文件還大,所以實際使用過程中需要結合具體情況,在上述兩種增量方式中選擇。
資源覆蓋率統計
有了前端資源的離線和更新機制,就要考慮在每次新資源包發布後統計新版本的更新覆蓋率。這對於增量更新尤為重要,如果發現某個版本的使用為0或接近0,該版本就無需在維護。方式有很多中,最簡單的就是上報版本號,每次PV統計時帶上版本號,最後根據PV中的版本號來統計訪問不同版本上用戶的分布情況。
【轉】基於localStorage的資源離線和更新技術