纯前端实现自动更新检测

4,232 阅读4分钟

转自公众号:前端帮

原文地址:mp.weixin.qq.com/s/nIZrk_5mM…

背景

我经常使用的一个云开发网站LAF,为了每次用起来方便,我是从来都不关闭这个标签页的,有时候进入页面,就发现一个弹窗,提示我有新版本,点击即可更新。

我还纳闷pc端网站怎么会有这样的功能,压根就不需要啊(内心OS:这产品**吧)!后面一想,现在的网站基本都是基于SPA开发的,跳转页面不会导致页面刷新,这样的话有了新版本时不刷新页面就无法更新。更何况还有我这种从不关闭某个标签页的,原来小丑是我自己~

技术揭秘

猜想可能的实现方案:

  • 使用websocket,有新版本时后端告诉前端,或者用SSE实时通知前端。
  • 让后端写个接口,每次前端部署更新了,后端同步更新版本号,前端轮询拿到最新版本号,和本地旧版本号对比。

其实仅看这两种,个人感觉第二种反而比第一种要好,没必要为了一个版本更新用上服务端推送。

因为版本号在后端就是一个静态数据,且传输数据量小到可以忽略不计,所以即使用轮询,对服务器和网络压力也不高。

说这么多,不如直接打开f12,看看人家是怎么做的。惭愧,network里没找到,可能人家就是用的推送吧,需要的时候才会推送。

纯前端实现

题外话:生活在大数据时代,有时候真是感觉自己被监控了,想啥来啥,这不,第二天就刷到渡一袁老师的视频,讲的就是这个自动检测更新。

思路

SPA项目都是只有一个html入口文件,通过引用一堆js css来实现所有的功能,那是不是只要检测到我们当前访问的这个html文件和服务端的不一样了,就认为是需要更新了。对,就是这样。那怎么检测呢?

实现

建个vue3项目演示一下

npm create vue@latest

npm run dev跑一下开发环境,没问题。

直接运行npm run build打包,我在本地起一个nginx,指向这个项目的dist目录

访问一下auto-update.localhost,没问题。

注意看地址栏,是打包后的代码了。

src下建一个auto-update.js,在main.js里引入

import './auto-update.js'

以下代码逻辑非常简单,且有详细的注释:

// 保存旧的html代码字符串
let oldHtml;

// 从服务端获取最新的html代码
async function fetchHtml() {
    // fetch('/index.html')获取的就是html文件,
    // 再用text()转为字符串
    // 加上时间戳避免缓存
    return await fetch(`/index.html?timestamp=${+new Date()}`)
        .then(res => res.text())
}

// 判断需不需要更新
async function needUpdate() {
    const newHtml = await fetchHtml()
    // 默认不需要更新
    let result = false
    if (oldHtml && oldHtml !== newHtml) {
        // 有旧值,并且新旧值不同,才需要更新
        result = true
    }
    // 没有旧值,或者新旧值一样,就无需更新
    
    // 无论用户更不更新版本,都更新旧值,
    // 这样当用户选择不更新时就不会再提示了
    // 除非刷新页面
    oldHtml = newHtml
    return result
}

// 递归调用,3秒一次
function autoRefresh() {
    setTimeout(async () => {
        if (await needUpdate()) {
            console.log('需要更新')
            const res = confirm('有新版本,点击确定更新')
            if (res) {
                location.reload()
            }
        }
        autoRefresh()
    }, 3000)
}

autoRefresh()

打包部署后,来测试一下。 可以看到不需要用户操作,且纯前端就做到了实时检测更新。当然我这里服务器就在本地,实际会有一个部署到服务器的过程。

这种做法适用于以下三种情况:

  • html文件内没有过多固定代码,即所有的css和js都通过打包工具打包到单独的文件中(有的人喜欢在index.html里写一些全局的固定代码),且没有很多分包的情况,毕竟分包越多,引入的就越多,整个index.html文件就越大。

  • 推荐需要经常更新静态代码的网站使用,不经常更新的就没必要了。

  • 对实时更新需求强烈的网站使用