• 前端重新部署如何使用WebWorker优雅地通知用户刷新网页?


    背景

    当周五晚上我正准备享用美味的宵夜时,突然接到了一个紧急消息,组里的前端系统出现了bug。我皱起了眉头,放下手中的美食,立即打开了钉钉,查看了具体情况。

    原来,这个bug实际上是前几天才解决过的问题。我用手指在屏幕上滑动,果然发现了解决之道——只需简单地刷新页面。原因竟是用户一直停留在页面上,而新版本发布后,他们没有及时刷新页面,导致无法获取到最新的资源。

    这让我想起了一个有趣的小故事:有一次,一个小村庄里的农夫决定要建造一个全新的小桥,以便于村民们更便利地过河。他精心设计了桥梁,使用了最先进的材料。然而,当桥梁完工后,他发现村民们仍然习惯于原来的狭窄破旧的木桥,而不愿意使用新桥。原来,他们根本不知道有新桥的存在,因为从来没有人告诉过他们。

    解决方案

    1. 添加manifest.json文件记录版本信息:这是一个很好的做法,可以方便地记录前端应用的版本信息。

    2. 打包时写入当前时间戳信息:这种方式可以确保每次打包都会更新manifest.json中的版本信息,以便后续的版本比较。

    3. 引入检查更新逻辑:在入口JS中引入检查更新的逻辑是非常好的,这样可以确保应用启动时就会进行版本检查。

    • 路由守卫检查更新:使用路由守卫进行检查更新是一个不错的选择,因为它可以确保在用户每次导航到页面时都会进行检查。

    • 使用Worker轮询检查更新:这种方法也可以,但需要注意轮询的频率,过于频繁的轮询可能会给服务器带来不必要的负担。而且使用Worker可能会增加一些复杂性。

    案列

    1. public文件夹下创建一个manifest.json文件,用于记录版本信息。在public文件夹下新建manifest.json文件,并写入以下内容:
    {
      "timestamp": 0,
      "msg": "这是一个示例更新提示信息"
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1. 修改public/index.html文件,将标签中的修改为你项目的名称,并在标签中添加以下代码,用于引入manifest.json文件:
    <link rel="manifest" href="<%= BASE_URL %>manifest.json" />
    
    • 1
    1. 在Vue项目中的入口文件src/main.js中,引入检查更新的逻辑:
    import Vue from 'vue'
    import App from './App.vue'
    import router from './router'
    
    Vue.config.productionTip = false
    
    // 引入检查更新逻辑
    import '@/utils/checkUpdate'
    
    new Vue({
      router,
      render: h => h(App)
    }).$mount('#app')
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    1. 创建一个工具类文件src/utils/checkUpdate.js,用于实现检查更新的逻辑:
    import router from '@/router'
    import { Modal } from 'ant-design-vue'
    
    if (process.env.NODE_ENV === 'production') {
      let lastEtag = ''
      let hasUpdate = false
      let worker = null
    
      async function checkUpdate() {
        try {
          let response = await fetch(`/manifest.json?v=${Date.now()}`, {
            method: 'head'
          })
          let etag = response.headers.get('etag')
          hasUpdate = lastEtag && etag !== lastEtag
          lastEtag = etag
        } catch (e) {
          return Promise.reject(e)
        }
      }
    
      async function confirmReload(msg = '', lastEtag) {
        worker &&
          worker.postMessage({
            type: 'pause'
          })
        try {
          Modal.confirm({
            title: '温馨提示',
            content: '系统后台有更新,请点击“立即刷新”刷新页面\n' + msg,
            okText: '立即刷新',
            cancelText: '5分钟后提示我',
            onOk() {
              worker.postMessage({
                type: 'destroy'
              })
              location.reload()
            },
            onCancel() {
              worker &&
                worker.postMessage({
                  type: 'recheck',
                  lastEtag: lastEtag
                })
            }
          })
        } catch (e) {}
      }
    
      router.beforeResolve(async (to, from, next) => {
        next()
        try {
          await checkUpdate()
          if (hasUpdate) {
            worker.postMessage({
              type: 'destroy'
            })
            location.reload()
          }
        } catch (e) {}
      })
    
      worker = new Worker(
        new URL('../worker/checkUpdate.worker.js', import.meta.url)
      )
    
      worker.postMessage({
        type: 'check'
      })
      worker.onmessage = ({ data }) => {
        if (data.type === 'hasUpdate') {
          hasUpdate = true
          confirmReload(data.msg, data.lastEtag)
        }
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    1. 创建一个Worker文件src/worker/checkUpdate.worker.js,用于实现Worker的逻辑:
    let lastEtag
    let hasUpdate = false
    let intervalId = ''
    async function checkUpdate() {
      try {
        let response = await fetch(`/manifest.json?v=${Date.now()}`, {
          method: 'get'
        })
        let etag = response.headers.get('etag')
        let data = await response.json()
        hasUpdate = lastEtag !== undefined && etag !== lastEtag
        if (hasUpdate) {
          postMessage({
            type: 'hasUpdate',
            msg: data.msg,
            lastEtag: lastEtag,
            etag: etag
          })
        }
        lastEtag = etag
      } catch (e) {
        return Promise.reject(e)
      }
    }
    
    addEventListener('message', ({ data }) => {
      if (data.type === 'check') {
        checkUpdate()
        intervalId = setInterval(checkUpdate, 5 * 60 * 1000)
      }
      if (data.type === 'recheck') {
        hasUpdate = false
        lastEtag = data.lastEtag
        intervalId = setInterval(checkUpdate, 5 * 60 * 1000)
      }
      if (data.type === 'pause') {
        clearInterval(intervalId)
      }
      if (data.type === 'destroy') {
        clearInterval(intervalId)
        close()
      }
    })
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    以上就是一个简单的案例,你可以在Vue项目中测试一下自动检查更新并提示用户刷新页面的功能。记得在实际项目中根据具体情况做适当的调整和优化。

  • 相关阅读:
    Java代码审计——WebGoat CSRF (上)
    注塑车间是否需要导入MES系统?
    Java 协程终于要来了
    Linux虚拟机和开发板scp命令互传文件
    C++ concept的概念和使用
    学生HTML个人网页作业作品 简单的IT技术个人简历模板html下载 简单个人网页设计作业 静态HTML个人博客主页
    项目总结——深入浅出socket网络编程
    AOP切入点表达式
    vue3学习笔记(兄弟组件传参)
    Electron+Vue+pyinstaller服务打包
  • 原文地址:https://blog.csdn.net/qq_41961239/article/details/136618874