记一次Service Worker“踩坑”

553 阅读3分钟

前言

最近公司的h5项目发现经常更新后,更新的内容没有及时展示出来,有延迟,怀疑有缓存,遂进行项目配置排查。最后发现是因为以前的项目里面有使用offline-plugin配置service-worker实现项目缓存机制。

什么是Service Worker

在MSD上面关于Service Worker是这样描述的:Service worker 是一个注册在指定源和路径下的事件驱动 worker。它采用 JavaScript 文件的形式,控制关联的页面或者网站,拦截并修改访问和资源请求,细粒度地缓存资源。你可以完全控制应用在特定情形(最常见的情形是网络不可用)下的表现。Service worker 本质上充当 Web 应用程序、浏览器与网络(可用时)之间的代理服务器。这个 API 旨在创建有效的离线体验,它会拦截网络请求并根据网络是否可用来采取适当的动作、更新来自服务器的的资源。它还提供入口以推送通知和访问后台同步 API。 通俗来讲,Service Worker就是一个可以实现在浏览器进行离线缓存的代理服务器API, 利用它的这个机制可以实现定制化缓存或者将整个应用离线缓存。

更详细的信息可以前往MDN官网查看:

developer.mozilla.org/zh-CN/docs/…

解决过程

知道了问题是怎么产生的,那么解决问题就变得清晰多了。解决这个问题有三个办法。

  1. 在使用offline-plugin配置service-worker时有一个配置项responseStrategy(资源读取策略),它有两个值, 'cache-first'(缓存优先)和'network-first'(服务器资源优先)。默认是'cache-first',可以改为'network-first'。这样每次都会优先从服务器拿资源。
  2. 在使用offline-plugin配置service-worker时设置index.html文件不缓存。
  3. 直接去掉Service Worker

由于项目中其实对Service Worker的缓存机制并不是那么需要,所以我就决定直接把Service Worker去掉。于是我把项目中相关的Service Worker注册代码都去掉了。正当我心里美滋滋想着解决完这个缓存问题早点回家时,现实告诉我生活没有那么简单。在我把项目打包上线准备提包走人时,产品经理突然打了个电话过来,说为啥更新的内容还没显示出来,是不是缓存问题还没解决?我感觉到不对劲,不应该啊,我都把相关代码注释了,应该不会有缓存问题了呀。说时迟,那时快。我赶紧打开电脑,看一下到底怎么回事,结果发现,还是Service Worker的问题,我把代码注销掉并没有起到效果。后来经过仔细排查发现,终于发现了原因:

由于之前登录过的用户已经在浏览器注册了Service Worker, 把代码直接注释掉并不会删除已注册的Service Worker。同时,由于直接注释项目里的相关代码,导致不会生成新的Service Worker相关配置文件,但是服务器上面依旧有旧的sw.js文件,这就导致没办法通知浏览器的Service Worker更新。所以,想要成功卸载Service Worker,第一步先要修改Service Worker文件,使其能获取最新的代码,然后加入卸载用户浏览器的Service Worker代码。才能彻底删除Service Worker。

解决方法

第一步:修改Service Worker文件,使其能获取最新的代码,有两个办法:

  1. 在服务器上找到对应的文件直接修改或者使用offline-plugin修改配置responseStrategy为'network-first'

第二步:在项目入口处添加卸载代码:

// 卸载sw
if ('serviceWorker' in navigator) {
  try {
    navigator.serviceWorker.getRegistrations().then(registrations => {
      registrations.forEach(registration => {
        registration.unregister().then(() => {
          console.log('卸载成功')
        })
      })
    })
  } catch(err){
    console.log('err', err)
  }
}

总结

最后,通过此次事件,也让我对Service Worker的了解更深。也希望这篇文章能够帮助到大家少点踩坑,少点bug早下班~