vue2浏览器端自动检测更新

能不能做一个提醒用户页面更新了,需要刷新一下页面的功能,这样用户就可以体验到最新的功能。而不需要我们一个一个地去提醒。

直接上代码:

//autoUpdate.js

import { MessageBox } from 'element-ui';


let lastScripts = [];
/* 获取 html 中 js 资源名称 */
async function extractNewScripts (html) {
 const scriptReg = /<script.*src=["'](?<src>[^"']+)/gm;
 let result = [];
 let match;
 while ((match = scriptReg.exec(html))) {
   result.push(match.groups.src);
   console.log(result);
}
 return result;
}

/* 判断浏览器是否需要更新数据 */
async function needUpdate () {
 // const newScripts = await extractNewScripts(await fetch('/?_timestamp=' + Date.now()).then(resp => resp.text()));
 const newScripts = await extractNewScripts(await fetch('/').then(resp => resp.text()));
 if (!lastScripts.length) {
   lastScripts = newScripts;
   return false;
}
 let result = false;
 if (newScripts.length !== lastScripts.length) {
   result = true;
} else {
   for (let i = 0; i < lastScripts.length; i++) {
     if (lastScripts[i] !== newScripts[i]) {
       result = true;
       break;
    }
  }
}
 lastScripts = newScripts;
 return result;
}

/* 延时时间 20s */
const DURATION = 20000;

/* 自动刷新 */
export const autoRefresh = () => {
 setTimeout(async () => {
   const willUpdate = await needUpdate();
   console.log(willUpdate);
   if (willUpdate) {
     MessageBox.confirm('页面有更新,点击确定刷新页面?', '提示', {
       confirmButtonText: '确定',
       cancelButtonText: '取消',
       type: 'warning'
    }).then(() => {
       // location.reload(true);来强制刷新页面并绕过缓存。如果不加 true,浏览器可能会从其缓存中获取页面
       location.reload(true);
    }).catch(() => { });
  }
   autoRefresh();
}, DURATION);
}

 

//vue.config.js

module.exports = {

 configureWebpack: {
   output: {
     filename: `app-${new Date().getTime()}.js` // 修改文件名为你想要的名称  
  }
}
}

 

大致思路是这样的,在 autoRefresh,js 中有个 autoRefresh 函数,每 20s 执行一次,它会每次请求根路径,去判断获取的 html 文件,而后通过正则去判断 script 标签中 js 文件名的变化,如果有变化,就会弹框提示用户去更新。

这个逻辑应该不难理解,不过,我们还需要通过 Nginx 的配置来做适当的调整。

比如:Nginx 配置 add_header Cache-Control “no-cache”,此时浏览器不直接使用缓存,而是每次向服务器发送请求验证资源是否过期,如果没有过期使用缓存中的数据,如果过期了重新获取服务器中的数据。那么这里加时间戳就没有意义了。

再比如:Nginx 配置 add_header Cache-Control “max-age=86400”;缓存一天(可以设置长一点,我记得默认都很久的,js,css15 天的,图片 30 天,html 没有设置缓存时间),此时,在一天之内浏览器获取缓存中的数据,那么如果服务器中的数据发生了变化,此时加上时间戳就是有意义的了,因为不加时间戳,缓存没有过期的时候请求 index.html 文件的时候,还是取缓存中的数据,加上时间戳,浏览器会将其视为新的资源重新下载。

由于我们 Nginx 配置的是 add_header Cache-Control “no-cache”,就不用加时间戳了。

不过第二种做法,还有一丝丝的问题,我们来假设一下

当用户打开了页面,而后关闭,过了比过期时间还要久的时候再打开页面,在此之前服务器的资源更新了,那么页面会获取最新的数据,在判断的时候 lastScripts 首先为空,而后 20s 再次获取是最新的 html, 此时比较就没问题。

当用户打开了页面,而后关闭,此时服务器的资源更新,资源还没过期,用户打开页面,此时 lastScripts 也是存最新的 html,这样就有问题了,因为此时应该提醒用户可以刷新一下页面。如何解决?

vue2 浏览器端自动检测更新

这样用户就知道我的页面是不是最新的了。

留了一个小问题,我希望后续可以解决一下,大家有没有解决这个问题的办法,期待你的分享。

 

上面的方案只是其中的一种,我们还可以做其他的,比如:websocket 。比如:后台写个类似 APP 更新的功能,只不过这里需要轮询。但这两种方案都需要后端配合,还是比较麻烦的,而且一个是需要长连接,一个是需要访问数据库,更加的消耗资源。所以之前的方案应该是一个更加优化的解法,如果把之前留的那个小问题解决了,我觉得它会是这些方法中最优的解法,因为不需要进行验证资源是否过期了,减少了很多 304 请求。

 

 

 

 

© 版权声明

☆ END ☆
喜欢就点个赞吧
点赞0 分享
图片正在生成中,请稍后...