1. PWA和Service Worker的關係javascript
PWA (Progressive Web Apps) 不是一項技術,也不是一個框架,咱們能夠把她理解爲一種模式,一種經過應用一些技術將 Web App 在安全、性能和體驗等方面帶來漸進式的提高的一種 Web App的模式。對於 webview 來講,Service Worker 是一個獨立於js主線程的一種 Web Worker 線程, 一個獨立於主線程的 Context,可是面向開發者來講 Service Worker 的形態其實就是一個須要開發者本身維護的文件,咱們假設這個文件叫作 sw.js。經過 service worker 咱們能夠代理 webview 的請求至關因而一個正向代理的線程,fiddler也是幹這些事情),在特定路徑註冊 service worker 後,能夠攔截並處理該路徑下全部的網絡請求,進而實現頁面資源的可編程式緩存,在弱網和無網狀況下帶來流暢的產品體驗,因此 service worker 能夠看作是實現pwa模式的一項技術實現。html
2. service worker簡介前端
注意事項vue
生命週期java
工做流程webpack
註冊web
if(navigator && navigator.serviceWorker) { navigator.serviceWorker.register('/service-worker.js').then(function (registration) { console.log(registration) }).catch(function (err) { console.log(err) }) }
安裝chrome
var cacheVersion = 'test_2017122608'; // 安裝服務工做線程 self.addEventListener('install', function(event){ // 須要緩存的資源 var cacheFiles = [ '/dist/index.html', '/dist/js/index_async_bundle.js' ]; console.log('service worker: run into install'); event.waitUntil(caches.open(cacheVersion).then(function(cache) { return cache.addAll(cacheFiles); })); });
激活npm
// 新的service worker線程被激活(其實和離線包同樣存在"二次生效"的機理) self.addEventListener('activate', function (event) { console.log('service worker: run into activate'); event.waitUntil(caches.keys().then(function (cacheNames) { return Promise.all(cacheNames.map(function (cacheName) { // 注意這裏cacheVersion也能夠是一個數組 if(cacheName !== cacheVersion){ console.log('service worker: clear cache' + cacheName); return caches.delete(cacheName); } })); })); });
監聽編程
// 攔截請求並響應
self.addEventListener('fetch', function (event) { console.log('service worker: run into fetch'); event.respondWith(caches.match(event.request).then(function (response) { // 發現匹配的響應緩存 if(response){ console.log('service worker 匹配並讀取緩存:' + event.request.url); return response; } console.log('沒有匹配上:' + event.request.url); return fetch(event.request); /*var fetchRequest = event.request.clone(); return fetch(fetchRequest).then(function(response){ if(!response || response.status !== 200 || response.type !== 'basic'){ return response; } var responseToCache = response.clone(); caches.open(cacheVersion).then(function (cache) { console.log(cache); cache.put(fetchRequest, responseToCache); }); return response; });*/ })); });
3. 前端資源緩存演進
4. 項目如何快速接入service worker
咱們是在業務代碼中經過register的方式引入service-worker.js, 那問題就變爲如何在註冊服務工做線程的位置引入版本號呢,咱們能夠經過sw-register-webpack-plugin來解決該問題,其思路是將服務工做線程的註冊放在一個單獨的文件中(sw-register.js),而後自動在頁面入口(例如index.html)寫入一段JS腳原本動態加載sw-register.js文件,這裏sw-register.js的加載路徑是帶有實時時間戳的,而生成的sw-register.js文件內容中註冊service-worker.js的位置自動攜帶構建版本號參數(默認是當前構建時間),該插件配置以下(基於webpack構建的項目):
let SwRegisterWebpackPlugin = require('sw-register-webpack-plugin') ... plugins: [ new SwRegisterWebpackPlugin({ filePath: path.resolve(__dirname, '../src/sw-register.js') }) ]
已緩存資源文件如何更新呢?上述插件只是解決了service-worker.js文件自己的更新的問題(保證每次構建部署後會新啓一個服務工做線程),但對於service-worker.js文件中定義的cacheFiles而言,當咱們修改了已緩存文件後如何來更新緩存呢,個人項目是基於vue.js + webpack,打包後的JS文件是[name].[hash].[ext]格式,從前面的介紹可知資源的緩存也是基於url(做爲key)來的,不可能每次構建後都手動去調整service-worker.js文件內容中cacheFiles的路徑值吧,應該是將構建後的文件名(包括路徑)直接放到service-worker.js內容中,看到這裏你應該想到了有webpack插件已經幫咱們作好了,那就是sw-precache-webpack-plugin,該插件會自動在dist目錄下生成service-worker.js文件,供給service worker運行,也就是說service-worker.js文件自己不須要咱們手動添加了,但問題是咱們如何自定義須要緩存的文件呢,該插件的配置參數會告訴你,個人項目該插件配置以下:
// 生成service-worker.js和配置緩存清單 new SwPrecacheWebpackPlugin({ cacheId: 'attendance-mobile-cache', filename: 'service-worker.js', minify: true, dontCacheBustUrlsMatching: false, staticFileGlobs: [ 'dist/static/js/manifest.**.*', 'dist/static/js/vendor.**.*', 'dist/static/js/app.**.*' ], stripPrefix: 'dist/' })
4. 調試service worker
5. 異常回滾(註銷)
某些場景下若是service worker使用出現異常,好比不一樣頁面間 service worker 控制的scope存在「重疊污染」的問題,那麼咱們就須要緊急回滾(撤銷)當前 service worker,在開發環境很好解決,咱們依然能夠經過Chrome Devtools來進行unregister, 那麼在線上環境已經有服務工做線程在運行的狀況下呢,咱們須要在新上線版本的service worker註冊前將被污染或者異常的service worker註銷掉,具體代碼以下:
if (navigator.serviceWorker) { navigator.serviceWorker.getRegistrations().then(function (registrations) { for (var item of registrations) { if (item.scope === 'http://localhost/attendance-mobile/dist/') { item.unregister(); } } // 註銷掉污染 Service Worker 以後再從新註冊... }); }
備註:文中部份內容摘選自Google開發者文檔
原文直通車