使用Service worker實現加速/離線訪問靜態blog網站
作者:Google 開發技術專家 (GDE) 楊波 (Alpha)
現在很流行基於 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 讓頁面渲染速度達到最高。
作者其他文章:
相關文章
- 使用Service Worker做一個PWA離線網頁應用網頁
- Service Worker學習與實踐(一)——離線快取快取
- service worker 對靜態資源進行快取快取
- 本地儲存Cookie、Storage、indexDB、ServiceWork離線訪問網站CookieIndex網站
- 為什麼網站使用CDN加速後,網站訪問速度反而變慢了?網站
- 前端快取機制提升網站效能 - Service Worker前端快取網站
- Serverless實踐-靜態網站託管Server網站
- 利用ServiceWorker實現頁面的快速載入和離線訪問
- blog-engine-06-pelican 靜態網站生成 支援 markdown 和 reST 語法網站REST
- 用SERVICE LOCATOR 模式實現命名訪問 (轉)模式
- 訪問github出現無法訪問此網站Github網站
- 網站靜態化思想網站
- 網站偽靜態和純靜態區別網站
- 《Dokcer的使用》(四) 實戰之Nginx+靜態網站部署Nginx網站
- 使用 Hexo 為自己在 Github 上建一個靜態 Blog部落格 站點HexoGithub
- 使用Java和Maven(JBake)生成靜態網站 - optaplannerJavaMaven網站
- 關於大型網站技術演進的思考(十一)--網站靜態化處理—動靜分離策略(3)網站
- 日記13(靜態網站)網站
- 網站提速-偽靜態(3)網站
- 談談網站靜態化網站
- Service Worker初探
- Openshift 4.4 靜態 IP 離線安裝系列:準備離線資源
- SpringBoot靜態資源訪問Spring Boot
- SpringMVC配置靜態資源訪問SpringMVC
- 如何使用 AWS 的 CloudFront(全球分發網路)服務助力企業網站海外訪問加速Cloud網站
- 如何使用gohugo/hugo建立一個靜態網站?Go網站
- 關於大型網站技術演進的思考(十七):網站靜態化處理—滿足靜態化的前後端分離(9)網站後端
- 關於大型網站技術演進的思考(十七)--網站靜態化處理—滿足靜態化的前後端分離(9)網站後端
- springboot+themeleaf+bootstrap訪問靜態資源/無法訪問靜態資源/圖片Spring Boot
- Linux配置靜態IP解決無法訪問網路問題Linux
- Nginx實現動靜分離Nginx
- Web靜態資源加速Web
- PWA進階:Service Worker一問一答
- Wordpress教程:一鍵實現WP部落格靜態檔案CDN加速
- 建站教程:使用GitHub和Hexo搭建免費靜態BlogGithubHexo
- 最佳實踐:使用阿里雲CDN加速OSS訪問阿里
- Service Worker入門
- ShardingSphere-proxy +PostgreSQL實現讀寫分離(靜態策略)SQL