一直以来只知道
HTTP Cache
是有缓存总量上限的,但是不知道对于单个文件的体积大小也是有限制的。
在这次接盘的3D可视化项目中就遇到了这个问题。因为模型文件体积比较大,在实际使用中经常会反馈说载入时间过长。所以在拿到服务器权限之后就改了一下 Nginx
的配置文件开启了静态资源的 HTTP cache
,以为完事大吉就和一线说载入时间慢的问题解决好了。现在进入项目会使用本地缓存,在第一次载入的时候会慢一些,后面再次进入就会快很多了。
但是实际使用中反馈过来的时依旧会有很长的载入时间。以为是 Nginx
的配置项写错了,就又去确认了一下。确实是开启了缓存的,首页的各种静态资源也是会被缓存,但是等我进入到模型展示页的时候就发现问题了!
最外层展示的模型是可以被缓存的,但是操作数据下钻之后开始展示内部模型从 Network
面板中看到的 glb
模型文件不是每一个都会从 disk cache
读取,有一些模型依旧会发起请求。
所以就想着浏览器是不是可以有配置项可以修改,但是并没有(可以通过给快捷方式添加启动命令来修改,但不可能要求所有设备都这样做)。所以只能想其他法子来解决这个问题,自然就找到了 Service Worker
使用 Service Worker
其实很简单,一点也不麻烦,创建好 service-work.js
文件之后,注册一下就可以了直接在浏览器中看到效果了。
🌰 比如说创建这样的一个 service-work.js
文件:
// service-work.js
// 监听install事件
// self 就是 service worker
self.addEventListener('install', event => {
// 安装完成后,使用 addAll 进行文件缓存
event.waitUntil(
caches.open('my-cache').then(cache => {
return cache.addAll([
'/static/glb/workshop_a/base.glb',
'/static/glb/workshop_a/equipment_a.glb',
'/static/glb/workshop_a/equipment_b.glb',
'/static/glb/workshop_a/equipment_c.glb',
])
})
)
})
// 监听fetch事件
self.addEventListener('fetch', event => {
event.respondWith(
// 匹配缓存中是否有相同的请求资源
caches.match(event.request).then(response => {
// 如果有相同的资源,则直接返回。否则,通过fetch方法请求资源
return response || fetch(event.request).then(fetchResponse => {
// 如果是GLB文件,将其缓存到磁盘
if (event.request.url.endsWith('.glb')) {
return caches.open('my-cache').then(cache => {
// 将请求响应内容复制并添加到缓存中
cache.put(event.request, fetchResponse.clone());
// 返回请求响应内容
return fetchResponse;
});
} else { // 如果不是GLB文件,直接返回请求响应内容
return fetchResponse;
}
})
})
)
})
上面使用了两种方式来缓存,一种是直接在注册的时候通过 cache.addAll 把对应的文件请求并缓存在本地。
一种是通过监听 fetch
事件的发起,通过匹配请求的 url
中是否有对应的 .glb
后缀来实现缓存。
然后到 main.js
中注册一下:
// main.js
// ...其他业务代码
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js')
.then(registration => {
console.log('Service Worker registered with scope:', registration.scope);
})
.catch(error => {
console.error('Service Worker registration failed:', error);
});
}
// 其他业务代码...
然后就可以在浏览器的 Network
面板中看到效果了:
模型的加载缩减到了原本耗时的 1/10
左右,但是模型载入的解析事件还是会按照演示时的设备性能有一些编码,因为使用了压缩技术把模型压缩了。
😫 遇到的问题
🎃 注册 service worker
时提示 The script has an unsupported MIME type ('application/json').
使用 navigator.serviceWorker.register('./service-worker.js')
注册时提示:
Service Worker registration failed: DOMException: Failed to register a ServiceWorker for scope ('http://localhost/') with script ('http://localhost/service-worker.js'): The script has an unsupported MIME type ('application/json').
因为我使用的 Vue 项目,所以把 service-worker.js
移动到 public
目录下,并且改写为绝对路径(navigator.serviceWorker.register('/service-worker.js')
)解决了问题。
🎃 需要注意 service worker
注册的作用域
Service worker
是有作用域的,如果你把他放到 https://domain.com/js
目录下,那么 service worker
只会在 /js
目录中生效。除非你在注册时声明好 scope
作用域,比如说 navigator.serviceWorker.register("/service-worker.js", { scope: "/" })
🎃 需要开启 HTTPS
Service worker
是需要开启 HTTPS
的,如果项目没有开启 HTTPS
那么 Service worker
并不会被激活注册。在本地开发的时候可以通过访问 localhost
这样的特殊域名来测试。
相关链接
Service Worker API - Web APIs | MDN
Using Service Workers - Web APIs | MDN
Making PWAs work offline with Service workers - Progressive web apps | MDN
Web Storage | Articles | web.dev
What is Chrome default cache size limit? - Super User