• Vue如何实现自动检测更新提醒
  • 发布于 2个月前
  • 292 热度
    0 评论
几天前,我和运营说,某个功能做好了,你们可以使用了,但是过了两天,和我反馈说,我这边没有这个功能呀,我看了下,权限也给了,回头一想是不是页面一直开着,没刷新的缘故,结果刷新了一下页面就可以了。我这个时候再想能不能做一个提醒用户页面更新了,需要刷新一下页面的功能,这样用户就可以体验到最新的功能。而不需要我们一个一个地去提醒。

直接上代码:
// 堆代码 duidaima.com
//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",就不用加时间戳了。

不过第二种做法,还有一丝丝的问题,我们来假设一下:
1.当用户打开了页面,而后关闭,过了比过期时间还要久的时候再打开页面,在此之前服务器的资源更新了,那么页面会获取最新的数据,在判断的时候lastScripts首先为空,而后20s再次获取是最新的html, 此时比较就没问题。

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

下面是效果图:

这样用户就知道我的页面是不是最新的了。留了一个小问题,我希望后续可以解决一下,大家有没有解决这个问题的办法,期待你的分享。

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