餘爲前端菜鳥,感姿式水平匱乏,難觀前端之大局。遂決定循前端知識之脈絡,以興趣爲引,輔以幾分堅持,望於己能解惑致知、於同道能助力一二,豈不美哉。html
本系列代碼及文檔均在 此處前端
service worker是一個由來已久的HTML5 API,旨在建立持久的離線緩存。相似於web worker,都是在瀏覽器後臺單獨開的一個線程內工做,能夠向客戶端推消息,不可操做dom。git
service worker有本身的worker context,能夠攔截請求和返回,緩存文件,必須在HTTPS或者本地環境下運行,異步實現,內部大部分經過Promise實現github
依賴Cache API,依賴FTML5 fetch API,依賴Promise實現離線緩存功能web
parsed -> installing -> installed -> activating -> activated -> redundantchrome
註冊在主線程中進行api
if (navigator.serviceWorker) {
// register異步方法
navigator.serviceWorker.register('./sw.js', { scope: '/' }).then(() => {
console.log('sw service worker 註冊成功')
console.log('parsed ----> installing')
}).catch((err) => {
console.log(err)
})
}
複製代碼
在worker的腳本文件中監聽install事件,能夠維護初始緩存列表瀏覽器
self.addEventListener('install', (event) => {
// 確保安裝完成前完成下面的操做
event.waitUntil(
// 建立一個cache
caches.open('v1').then((cache) => {
// cache是緩存實例
// 調用該實例的addAll方法提早加載相關文件進緩存
return cache.addAll([
'/html/test.js',
'/html/default.html'
])
})
console.log('installing ----> installed ----> activating')
)
// self.skipWaiting() 直接進入activate
})
複製代碼
worker安裝完成後會轉爲installed/activating狀態,在知足如下條件之一時能夠轉爲activate狀態緩存
activated狀態會觸發activate回調,在worker監本中監聽activate事件app
self.addEventListener('activate', function (event) {
event.waitUntil(
caches.keys().then(function (cacheNames) {
return Promise.all(
cacheNames.filter(function (cacheName) {
return cacheName != 'v1';
}).map(function (cacheName) {
// 清除舊的緩存
return caches.delete(cacheName);
})
)
})
console.log('activating ----> activated')
)
// self.clients.claim() 獲取頁面控制權,舊的worker失效
})
複製代碼
激活後能夠控制頁面行爲,能夠處理功能事件,如fetch
, push
, message
符合worker的scope內的資源請求都會觸發fetch被控制
self.addEventListener('fetch', function (event) {
// 利用respondWith劫持響應
event.respondWith(
caches.open('v1').then(function (cache) {
return cache.match(event.request).then(function (response) {
// match到則返回不然直接請求
return response || fetch(event.request).then(function (response) {
// 404拋錯到catch處理
if (response.status === 404) {
throw new Error('nothing')
}
// 將response做爲value存入cache
// install時能夠進行緩存
// 劫持fetch時也能夠進行動態資源緩存
cache.put(event.request, response.clone());
return response;
}).catch((err) => {
// 返回cache storage裏存的默認頁面
return caches.match('/html/default.html');
});
});
})
);
});
複製代碼
localStorage是同步的,因此不能用於service worker內的存儲,IndexedDB能夠用
安裝失敗、激活失敗、被新的worker取代時轉入廢棄狀態
當service worker腳本內容更新時,會安裝新的文件並觸發install,轉入installed/waiting狀態。此時舊的worker仍處於激活狀態,在頁面關閉後會被廢棄,此後新開頁面裏新的worker纔會生效
上圖爲更改sw.js
後刷新頁面的結果,關閉頁面重開後1497將是激活中的worker
通常爲24小時
// 跳過等待,直接進入activate
self.addEventListener('install', function (event) {
event.waitUntil(self.skipWaiting());
});
// actived以前更新客戶端
self.addEventListener('activate', function (event) {
event.waitUntil(
Promise.all([
// 更新客戶端全部的service worker
self.clients.claim(),
// 清理舊版本
caches.keys().then(function (cacheList) {
return Promise.all(
cacheList.map(function (cacheName) {
if (cacheName !== 'v1') {
return caches.delete(cacheName);
}
})
)
})
])
)
)}
複製代碼
主線程內每次註冊時進行更新
var version = '1.0';
navigator.serviceWorker.register('./sw.js').then(function (reg) {
if (localStorage.getItem('sw_version') !== version) {
// reg.update
reg.update().then(function () {
localStorage.setItem('sw_version', version)
});
}
});
複製代碼
debug時更新
self.addEventListener('install', function () {
if (ENV === 'development') {
// 每次刷新頁面從新註冊安裝時直接進入activate,確保最新
self.skipWaiting();
}
});
複製代碼
cacheStorage是在serviceworker規範中定義的接口,咱們可使用全局的caches訪問cacheStorage
caches經常使用api有: open
, match
, delete
, has
, keys
代碼位於github
本地利用koa-static
建一個靜態頁面的server
const Koa = require('koa')
const path = require('path')
const static = require('koa-static')
const app = new Koa()
const staticPath = './frontend/basic'
app.use(static(
path.join(__dirname, staticPath)
))
複製代碼
頁面中插入腳本
window.addEventListener('load', function () {
if (navigator.serviceWorker) {
navigator.serviceWorker.register('./sw.js').then(() => {
console.log('sw service worker 註冊成功')
}).catch((err) => {
console.log(err)
})
}
})
複製代碼
sw.js
見 github
offline模式下,能夠從cache中讀取文件緩存
不存在的資源路徑返回緩存好的default.html
二次訪問緩存list內的資源時劫持請求和響應,返回緩存內容
雖發表於此,卻畢竟爲一人之言,又是每日學有所得之筆記,內容未必詳實,看官老爺們還望海涵。