用户停留页面更新主动提醒刷新的一种方案

172 阅读1分钟

场景

对于单页面应用,用户一直停留在当前页面,网站更新了,路由跳转加载资源可能就会找不到,这时可以通过 window.onerror 监听资源加载失败来被动提醒用户,但如果不等用户操作,主动弹出提醒该怎么做呢?

fetch('')

一种方案是隔一段时间就请求网页源码,如果和当前网页源码不一致了就说明页面发生了更新。

一般打包后 index.html 肯定会发生变动。

setInterval(async () => {
  try {
    const res = await fetch('')
    const html = await res.text()
    if (window.latestHtml && window.latestHtml !== html) console.log('请刷新')
    window.latestHtml = html
  } catch (error) {
    //
  }
}, 60000)

Etag

也可以不请求整个 index.html,只请求 header 也是一种方案。

const res = await fetch('', { method: 'HEAD' })
console.log(res.headers.get('Etag'))

image.png

image.png

判断 Etag 的变化来提醒刷新。

Build Timestamp

还有一种思路是每次打包都创建一个文件,文件内容是打包时间戳,同样隔一段时间就请求这个文件,如果文件内容变化了就说明资源有了更新。

npm run build && node build-id.js

只需要在构建完成后跑一个脚本即可。

build-id.js 代码如下,将当前时间戳写到 dist/build-id.js 中,写入的是 36 进制的时间戳,稍微混淆下,太直白暴露构建时间也不太好。

const fs = require('fs')

fs.writeFileSync('./dist/build-id.js', Date.now().toString(36), 'utf-8')

dist/build-id.js

lruhqttv

每隔一定时间就请求这个文件,拿到时间戳判断是否有更新,这里用的是 js 类型文件,随便搞个类型也行。fetch 要加上参数 cache: 'reload' 或者 header 加上 'Cache-Control': 'no-cache' 不使用缓存。

setInterval(async () => {
  try {
    // const res = await fetch('build-id.js', {
    //   cache: 'reload'
    // })
    // or
    const res = await fetch('build-id.js', {
      headers: {
        'Cache-Control': 'no-cache'
      }
    })
    const id = await res.text()
    if (window.buildId && window.buildId !== id) console.log('请刷新')
    window.buildId = id
  } catch (error) {
    //
  }
}, 60000)