使用 Service worker 實現加速/離線訪問靜態 blog 網站

sztown 7年前發布 | 98K 次閱讀 瀏覽器 Web開發工具

現在很流行基于 GitHub page 和 markdown 的靜態 blog,非常適合技術的思維和習慣,針對不同的語言都有一些優秀的靜態 blog 系統出現,如 Jekyll/Ruby,Pelican/Python,Hexo/NodeJs,由于靜態內容的特性非常適合做緩存來加速頁面的訪問,就利用 Service worker 來實現加速,結果是除了 PageSpeed,CDN 這些常見的服務器和網絡加速之外,通過客戶端實現了更好的訪問體驗。

加速/離線訪問只需三步

1. 首頁添加注冊代碼

2. 復制代碼

將 https://alphayang.github.io/sw.js 保存到你的網站根目錄下。

3. 修改不緩存域名列表及離線狀態頁面

在你的 sw.js 中修改

打開 Chrome Dev Tools->Source,看看自己的 blog 都引用了哪些第三方資源,逐個加到忽略列表里。

在根目錄下添加 offline.html,在沒有網絡且緩存中也沒有時使用,效果如下:

在根目錄下添加 offline.svg,在無網絡時圖片資源請求返回該文件。

4. 加速效果

首頁加速后,網絡請求從 16 降為 1,加載時間從 2.296s 降為 0.654s,得到了瞬間加載的結果。

加速/離線原理探索

什么是 Service worker?

如上圖,Service worker 是一種由 Javascript 編寫的瀏覽器端代理腳本,位于你的瀏覽器和服務器之間。當一個頁面注冊了一個 Service worker,它就可以注冊一系列事件處理器來響應如網絡請求和消息推送這些事件。Service worker 可以被用來管理緩存,當響應一個網絡請求時可以配置為返回緩存還是從網絡獲取。由于 Service worker 是基于事件的,所以它只在處理這些事件的時候被調入內存,不用擔心常駐內存占用資源導致系統變慢。

Service worker 生命周期

Service worker 為網頁添加一個類似于 App 的生命周期,它只會響應系統事件,就算瀏覽器關閉時操作系統也可以喚醒 Service worker,這點非常重要,讓 Web App與 Native App 的能力變得類似了。

Service worker 在 Register 時會觸發 Install 事件,在 Install 時可以用來預先獲取和緩存應用所需的資源并設置每個文件的緩存策略。

一旦 Service worker 處于 activated 狀態,就可以完全控制應用的資源,對網絡請求進行檢查,修改網絡請求,從網絡上獲取并返回內容或是返回由已安裝的 Service worker 預告獲取并緩存好的資源,甚至還可以生成內容并返回給網絡語法。

所有的這些都用戶都是透明的,事實上,一個設計優秀的 Service worker 就像一個智能緩存系統,加強了網絡和緩存功能,選擇最優方式來響應網絡請求,讓應用更加穩定的運行,就算沒有網絡也沒關系,因為你可以完全控制網絡響應。

Service worker 的控制從第二次頁面訪問開始

在首次加載頁面時,所有資源都是從網絡載的,Service worker 在首次加載時不會獲取控制網絡響應,它只會在后續訪問頁面時起作用。

頁面首次加載時完成 install,并進入 idle 狀態。

頁面第二次加載時,進入 activated 狀態,準備處理所有的事件,同時 瀏覽器會向服務器發送一個異步 請求來檢查 Service worker 本身是否有新的版本,構成了 Service worker 的更新機制。

當 Service worker 處理完所有的事件后,進入 idle 狀態,最終進入 terminated 狀態資源被釋放,當有新的事件發生時再度被調用。

特點

  • 瀏覽器:Google Chrome,Firefox,Opera 以及國內的各種雙核瀏覽器都支持,但是 safari 不支持,那么在不支持的瀏覽器里 Service worker 不工作。

  • https:網站必須啟用 https 來保證使用 Service worker 頁面的安全性,開發時 localhost 默認認為是安全的。

  • non-block:Service worker 中的 Javascript 代碼必須是非阻塞的,因為 localStorage 是阻塞性,所以不應該在 Service Worker 代碼中使用 localStorage。

  • 單獨的執行環境:Service worker 運行在自己的全局環境中,通常也運行在自己單獨的線程中。

  • 沒有綁定到特定頁面:Service worker 能控制它所加載的整個范圍內的資源。

  • 不能操作 DOM:跟 DOM 所處的環境是相互隔離的。

  • 沒有瀏覽頁面時也可以運行:接收系統事件,后臺運行。

  • 事件驅動,需要時運行,不需要時就終止:按需執行,只在需要時加載到內存。

  • 可升級:執行時會異步獲取最新的版本。

實現加速/離線

Cache

網頁緩存有很多,如 HTTP 緩存,localStorage,sessionStorage 和 cacheStorage 都可以靈活搭配進行緩存,但操作太繁瑣,直接使用更高級 Service worker –本文的主人公。

添加 Service worker 入口

在 Web App 的首頁添加以下代碼

如果瀏覽器支持 Service worker 就注冊它,不支持還是正常瀏覽,沒有 Service worker 所提供的增強功能。

Service worker 控制范圍:

簡單情況下,將 sw.js 放在網站的根目錄下,這樣 Service worker 可以控制網站所有的頁面,同理,如果把 sw.js 放在 /my-app/sw.js 那么它只能控制 my-app 目錄下的頁面。

把 sw.js 放在 /js/ 目錄呢?更好的目錄結構和范圍控制呢?在注冊時指定 js 位置并設置范圍。

navigator.serviceWorker.register('/js/sw.js', {scope: '/sw-test/'}).then(function(registration) {

// Registration was successful

console.log('ServiceWorker registration successful with scope: ', registration.scope);

}).catch(function(err) {

// registration failed :(

console.log('ServiceWorker registration failed: ', err);

});

Service worker 實現

監聽三個事件:

install

install 時將所有符合緩存策略的資源進行緩存。

fetch

onFetch 做為瀏覽器網絡請求的代理,根據需要返回網絡或緩存內容,如果獲取了網絡內容,返回網絡請求時同時進行緩存操作。

activate

///////////

// Activate

///////////

function onActivate(event) {

log('activate event in progress.');

event.waitUntil(removeOldCache());

}

function removeOldCache() {

return caches

.keys()

.then((keys) => {

return Promise.all( // We return a promise that settles when all outdated caches are deleted.

keys

.filter((key) => {

return !key.startsWith(version); // Filter by keys that don't start with the latest version prefix.

})

.map((key) => {

return caches.delete(key); // Return a promise that's fulfilled when each outdated cache is deleted.

})

);

})

.then(() => {

log('removeOldCache completed.');

});

}

在 activate 時根據 version 值來刪除過期的緩存。

管理 Service worker

特定網站

1) Google Chrome

Developer Tools->Application->Service Workers,

在這里還有三個非常有用的復選框:

  • Offline: 模擬斷網狀態

  • Update on reload: 加載時更新

  • Bypass for network: 總是使用網絡內容

2) Firefox

只有在 Settings 里有一個可以在 HTTP 環境中使用 Service worker 的選項,適應于調試,沒有單獨網站下的 Service worker 管理。

3) Opera 及其它雙核瀏覽器同 Google Chrome

如果看到多個相同范圍內的多個 Service worker,說明 Service woker 更新后,而原有 Service worker 還沒有被 terminated。

瀏覽器全局

看看你的瀏覽器里都有哪些 Service worker 已經存在了。

1) Google Chrome

在地址欄里輸入:

chrome://serviceworker-internals/

可以看到已經有 24 個 Service worker 了,在這里可以手動 Start 讓它工作,也可以 Unregister 卸載掉。

2) Firefox

有兩種方式進入 Service worker 管理界面來手動 Start 或 unregister。

  • 菜單欄,Tool->Web Developer->Service workers

  • 地址欄中輸入: 

    about:debugging#workers

3) Opera 及其它雙核瀏覽器同 Google Chrome

更多

TODO:

  • Service workers 的更新需要手動編輯 version,每次發布新文章時需要編輯;

  • 使用 AMP 讓頁面渲染速度達到最高。

作者其他文章:

AR/VR/MR,Android開發者可以做些什么?

Android無處不在,Android開發者大有可為

與谷歌開發技術專家一起,開啟“I/O地圖開發技術”之旅

 

來自:http://mp.weixin.qq.com/s/y8zgMC7BIhdcms7qQG4oEw

 

 本文由用戶 sztown 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!