Service Worker 圖片加載失敗處理
git clone https://gitee.com/wjj0720/Service-Worker.git
運行 npm i
npm start
訪問 http://127.0.0.1:3000/pages/index.html
打開控制檯 刷新(由於demo做的是後加載 需刷新後 看效果)
ctrl + c 結束node服務 再次刷新頁面(從緩存裏面讀取 依然顯示頁面)
簡介
-
背景
有一個困擾 web 用戶多年的難題——丟失網絡連接。之前的嘗試 — AppCache — 看起來是個不錯的方法,但是,它假定你使用時會遵循諸多規則,如果你不嚴格遵循這些規則,它會把你的APP搞得一團糟。Service worker 最終要去解決這些問題。雖然 Service Worker 的語法比 AppCache 更加複雜,但是你可以使用 JavaScript 更加精細地控制 AppCache 的靜默行爲。有了它,你可以解決目前離線應用的問題,同時也可以做更多的事。 Service Worker 可以使你的應用先訪問本地緩存資源,所以在離線狀態時,在沒有通過網絡接收到更多的數據前,仍可以提供基本的功能(一般稱之爲 Offline First)。這是原生APP 本來就支持的功能,這也是相比於 web app,原生 app 更受青睞的主要原因。
-
什麼是Service Worker ?
Service Worker是瀏覽器在後臺啓動的一條服務Worker線程
-
功能和特性:
1. 一個獨立的 worker 線程,且只有一個。 2. 一旦被 install,就永遠存在,除非被 uninstall 3. 需要的時候可以直接喚醒,不需要的時候自動睡眠(此處有坑) 4. 可代理請求和返回,緩存文件,緩存的文件可以被網頁進程取到 5. 能向客戶端推送消息 6. 不能直接操作 DOM 7. 出於安全的考慮,必須在 HTTPS/localhost 環境下才能工作 8. 異步實現,內部大都是通過 Promise 實現
### 使用
1. 註冊
// 兼容判斷
if ("serviceWorker" in navigator) {
// 一般考慮加載問題 windoe.onload後加載
window.addEventListener("load", function() {
// scope 參數是選填的,可以被用來指定你想讓 service worker 控制的內容的子目錄
navigator.serviceWorker.register("/sw.js", {scope: '/'})
.then(function(registration) {
// 註冊成功
console.log( "ServiceWorker registration successful with scope: ", registration.scope )
})
.catch(function(err) {
// 註冊失敗
console.log("ServiceWorker registration failed: ", err)
});
})
}
2. 使用
const precacheVersion = 2
const precacheName = "precache-v" + precacheVersion
var precacheFiles = [
"/pages/index.html",
"/images/dmx.jpg",
"/images/broken.png"
]
/**新
- SW.js 瀏覽器會自動檢查差異性
- 發生變更 install 事件被觸發 此時,舊的 SW 還在工作,新的 SW 進入 waiting 狀態。
- 注意,此時並不存在替換接管,當你現在已經打開的頁面關閉時,那麼舊的 SW 則會被 kill 掉。
- 新的 SW 就開始接管頁面的緩存資源。 一旦新的 SW 接管,則會觸發 activate 事件。
*/
self.addEventListener("install", e => {
console.log("[ServiceWorker] Installed")
// skipWaiting() 方法跳過 waiting 狀態,然後會直接進入 activate 階段
self.skipWaiting()
e.waitUntil(
caches.open(precacheName).then(cache => {
// 如果其中有一個 加載失敗 那就代表着--這次啓動 GG
return cache.addAll(precacheFiles)
// cache.put(request, response).then(function() {
// // 成功緩存
// });
})
)
})
self.addEventListener("activate", e => {
console.log("[ServiceWorker] Activated")
e.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.map(thisCacheName => {
if ( thisCacheName.includes("precache") && thisCacheName !== precacheName ) {
return caches.delete(thisCacheName)
}
})
)
})
)
// 更新客戶端
// self.clients.claim()
})
// 監聽頁面的請求 (不僅僅是js請求)
self.addEventListener("fetch", e => {
e.respondWith(
caches.match(e.request).then(response => {
// 有緩存走緩存
if (response) {
return response
}
return fetch(e.request) .then(fetchResponse => {
// console.log('s-->', fetchResponse);
if (fetchResponse.ok) return fetchResponse;
// 加載失敗的情況下 入股是圖片 則返回默認圖片
if (isImage(e.request)) {
return returnBrokenImg()
}
}).catch(err => {
if ( isImage(e.request) ) {
return returnBrokenImg()
}
})
})
)
})
function isImage(fetchRequest) {
return fetchRequest.method === "GET" && fetchRequest.destination === "image";
}
function returnBrokenImg () {
return caches.match('/images/broken.png').then(response => response)
}
// 監聽頁面發來的消息
self.addEventListener('message', function (message, e) {
console.log('service接受到的數據--->', message, e);
sendMessageToPage('嘟嘟嘟')
});
// 向頁面發送消息
function sendMessageToPage (msg) {
self.clients.matchAll().then(function (clients) {
if (clients && clients.length) {
clients.forEach(function (client) {
client.postMessage(msg);
})
}
})
}
3. 客戶端更新
> 除了由瀏覽器觸發更新之外,如果24小時沒有更新,會強制更新。這意味着最壞情況下Service Worker會每天更新一次
//localStorage 存下 版本 運行時候對比
var version = 'precache-v3'
navigator.serviceWorker.register('/sw.js').then(function (reg) {
if (localStorage.getItem('sw_version') !== version) {
reg.update().then(function () {
localStorage.setItem('sw_version', version)
});
}
})
4. 客戶端消息
// 監聽serviceWorker 消息
navigator.serviceWorker.addEventListener('message', function (event) {
// 接受數據,
console.log('頁面接受的數據:', event);
});
// 發送消息
document.getElementById('sendMSG').addEventListener('click', function () {
console.log('綁定點擊事件,點擊後發送數據');
navigator.serviceWorker.controller.postMessage('嘀嘀嘀');
});
5. 應用案例
1. 攔截圖片加載失敗 返回默認圖片 案例 https://bitsofco.de/handling-broken-images-with-service-worker/
2. 藍湖 https://lanhuapp.com/
### 新鮮貨
1. https://github.com/jiahaog/nativefier#how-it-works
3. https://imgcook.taobao.org/project