Service Worker 图片加载失败处理

7次阅读

共计 3918 个字符,预计需要花费 10 分钟才能阅读完成。

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 实现
9. 基于 [web worker](http://www.ruanyifeng.com/blog/2018/07/web-worker.html)

使用
1. 注册
“`js
// 兼容判断
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

正文完
 0