什麼是workbox,workbox有什麼用途,爲何要使用它?在介紹workbox以前,咱們來先大體瞭解一下service worker,有助於咱們後面更好地去理解workbox。css
service worker是在瀏覽器後臺獨立於網頁運行的腳本,它可以實現對網絡請求進行緩存,並向網頁推送和同步信息的功能,使人更加興奮的是,它能夠實現離線的狀況下,也能看到咱們的網頁,極大提高了咱們的用戶體驗。html
service worker 已經獲得愈來愈多的瀏覽器的支持,包括蘋果、騰訊的X5內核。蘋果從safari11開始,已經開始支持了。支持狀況以下:前端
workbox 是 GoogleChrome 團隊推出的一套 Web App 靜態資源和請求結果的本地存儲的解決方案,該解決方案包含一些 Js 庫和構建工具,在 Chrome Submit 2017 上首次隆重面世。而在 workbox 背後則是 Service Worker 和 Cache API 等技術和標準在驅動。在 Workebox 以前,GoogleChrome 團隊較早時間推出過 sw-precache 和 sw-toolbox 庫,可是在 GoogleChrome 工程師們看來,workbox 纔是真正能方便統一的處理離線能力的更完美的方案,因此中止了對 sw-precache 和 sw-toolbox 的維護。那workbox能解決什麼問題呢?webpack
在service worker中,若是咱們要攔截並代理全部的請求,須要咱們手動去維護一套緩存列表。可是如今前端開發,多數用webpack、gulp、grant來構建前端的代碼,致使咱們的文件名可能會常常發生,這個時候,特別是中大型的多頁應用,緩存列表的內容可能會很是多,手動維護就顯得很是麻煩,維護成本也變得很高。web
這個時候,workbox的橫空出世,就是爲了解決上面的問題。gulp
下面來看下workbox的例子。api
1.在入口頁面的onload中,註冊一個service worker,註冊時引入緩存列表文件,也就是build.sw.js。
index.html數組
<script> // Register A service worker if ('serviceWorker' in navigator) { window.addEventListener('load', function() { navigator.serviceWorker.register(`./build.sw.js`) .then(function(registration) { // Registration was successful console.log('[success] register ') }, function(err) { // registration failed :( console.log('[fail]: ', err); }); }); <script> }
2.在build.sw.js頁面配置緩存列表和緩存策略瀏覽器
// 首先引入 Workbox 框架 importScripts('https://storage.googleapis.com/workbox-cdn/releases/3.3.0/workbox-sw.js'); // 註冊成功後要當即緩存的資源列表 workbox.precaching.precacheAndRoute([ { "url": "css/index.css", "revision": "835ba5c3" }, { "url": "images/xxx.png", "revision": "b1537bfs" }, { "url": "index.html", "revision": "b331f695" }, { "url": "js/index.js", "revision": "4d562866" } ]); // 緩存策略 workbox.routing.registerRoute( new RegExp(''.*\.html'), workbox.strategies.networkFirst() ); workbox.routing.registerRoute( new RegExp('.*\.(?:js|css)'), workbox.strategies.cacheFirst() ); workbox.routing.registerRoute( new RegExp('https://your\.cdn\.com/'), workbox.strategies.staleWhileRevalidate() ); workbox.routing.registerRoute( new RegExp('https://your\.img\.cdn\.com/'), workbox.strategies.cacheFirst({ cacheName: 'example:img' }) );
實現的效果以下:緩存
咱們來看下build.sw.js文件的內容,主要包含緩存列表和緩存策略。這裏面的內容不用咱們手動生成,workbox有三種方式生成,咱們可使用workbox-webpack-plugin、workbox-cli、workbox-build。咱們暫不討論具體的實現,在這裏,咱們先來了解一下預緩存列表和緩存策略這兩個東西。
若是咱們要緩存靜態資源,平時不會常常更新,只有到發版時纔會修改了資源的hash值,才須要從新更新的,那那 precache 預緩存應該是你所期待的。
workbox 提供了一種很是方便的 API 幫助咱們解決 precache 的問題,咱們可使用workbox.precaching來配置,配置格式以下:
workbox.precaching.precacheAndRoute([ { "url": "將要預緩存的文件 URL", "revision": "緩存的hash值" }, ])
路由請求緩存是指經過對匹配路由給文件採起不用的緩存方式,這個能夠經過workbox.routing.registerRoute來進行配置。 路由匹配的方式有三種:
1.經過字符串的方式進行匹配
// 能夠直接是當前項目下的絕對路徑 workbox.routing.registerRoute( 'path/to/logo.png', handler // handler 是作緩存策略的回調函數,一般指後面所會降到的 '緩存策略函數' ); // 也能夠是完整的帶完整 host 的 URL 路徑,這裏的 URL 必須是 https 的 workbox.routing.registerRoute( 'https://example.com/a/b/c.jpg', handler );
2.經過正則的方式進行匹配
workbox.routing.registerRoute( new RegExp('.*\.(js|css|jpg|png|gif)'), // 這裏是任何正則都行,只要能匹配得上的請求路由地址 handler );
3.經過回調函數的方式進行匹配
// 經過回調函數來匹配請求路由將會讓策略更加靈活 const customFun = ({url, event}) => { // 若是請求路由匹配了就返回true,也能夠返回一個參數對象以供 handler 接收處理 return false; }; workbox.routing.registerRoute( customFun, handler );
緩存策略是指對於匹配到的路由,採起何種方式進行緩存。 workbox提供了兩種配置緩存策略的方式
如下介紹workbox默認提供的幾種緩存策略,包含有五種,分別是:
這種策略的意思是當請求的路由有對應的 Cache 緩存結果就直接返回,在返回 Cache 緩存結果的同時會在後臺發起網絡請求拿到請求結果並更新 Cache 緩存,若是原本就沒有 Cache 緩存的話,直接就發起網絡請求並返回結果。 使用方式以下:
workbox.routing.registerRoute( match, // 匹配的路由 workbox.strategies.staleWhileRevalidate() );
這種策略就是當請求路由是被匹配的,就採用網絡優先的策略,也就是優先嚐試拿到網絡請求的返回結果,若是拿到網絡請求的結果,就將結果返回給客戶端而且寫入 Cache 緩存,若是網絡請求失敗,那最後被緩存的 Cache 緩存結果就會被返回到客戶端 使用方式以下:
workbox.routing.registerRoute( match, // 匹配的路由 workbox.strategies.networkFirst() );
這個策略的意思就是當匹配到請求以後直接從 Cache 緩存中取得結果,若是 Cache 緩存中沒有結果,那就會發起網絡請求,拿到網絡請求結果並將結果更新至 Cache 緩存,並將結果返回給客戶端。
workbox.routing.registerRoute( match, // 匹配的路由 workbox.strategies.cacheFirst() );
比較直接的策略,直接強制使用正常的網絡請求,並將結果返回給客戶端,這種策略比較適合對實時性要求很是高的請求。
workbox.routing.registerRoute( match, // 匹配的路由 workbox.strategies.networkOnly() );
這個策略也比較直接,直接使用 Cache 緩存的結果,並將結果返回給客戶端,這種策略比較適合一上線就不會變的靜態資源請求。
workbox.routing.registerRoute( match, // 匹配的路由 workbox.strategies.cacheOnly() );
在咱們的項目中,咱們以DomContentLoaded的時間做爲參考點,對比有加service worker 和未加的service worker狀況。
測試條件
以首頁爲例,在不一樣的網絡環境下,發起10次網絡請求,而後取平均值,做爲它們的最終結果,測試結果以下:
經過上面的數據能夠得出幾個結論:
在使用workbox的過程當中,會遇到一些問題,下面列出幾點,也算是作個總結:
在頁面註冊service worker的時候,儘可能註冊到項目的根目錄下,這樣才能最大的發揮service worker的做用
// build.sw.js最好放在項目的根目錄下,才能發揮最大的緩存效果 navigator.serviceWorker.register(`./build.sw.js`) // 若是這樣配置的話,就只有path目錄下面的文件才能實現緩存,其餘目錄,包括根目錄的都不能緩存 navigator.serviceWorker.register(`./path/build.sw.js`)
咱們先預設一下應用場景:假設你的項目在目錄 /app 下,必須保證在你的項目根目錄下有一個 app/sw.js 包含如下內容:
// 一般項目中的 sw.js 源文件都是經過這樣預留一個空數組的方式來預緩存內容列表的 workbox.precaching.precacheAndRoute([]);
這樣才能保證能將生成的預緩存內容列表內容注入到 Service Worker 文件中。
在通過一段時間的使用和思考之後,給出認爲較爲合理的緩存策略:
若是你們在使用過程當中有更友好的策略,麻煩也貢獻大家的策略,你們共同窗習,共同進步。
還有,要牢記,對於不在同一域下的任何資源,絕對不能使用 Cache only 和 Cache first。
須要注意的是,Service Worker 腳本除了域名爲 localhost 時能運行在 http 協議下之外,只能運行 https 協議下。
Google對web的標準化仍是遵循的,SW認爲POST請求就是象服務器提交資源,不存在緩存需求
參考文檔: