今天分享一个实现页面自动检测更新,而且不需要动服务端代码的方法,比较取巧,在非覆盖式发布的情况下可以简单使用。
背景和思路
有部分运营是不刷新页面的,当我们前端资源更新了,他可能还在使用老的资源。
目标是希望在我们前端资源更新的时候提示用户有资源更新,然后刷新页面获取最新的前端资源。
一个适合非覆盖式发布的前端应用的自动检测更新方法。
覆盖式发布 | 前后两次发布的资源没有差异,js 资源也不使用 hash 进行区分 |
非覆盖式发布 | 前后两次发布的资源会有差异,比如体现在 js 资源带上 hash 或者发布的版本号 |
所以,我们以构建之后 js 资源带 hash 的页面为例,如果有新的发布,那么 js 资源的链接就会发生改变,通过比较前后两次的资源地址来判断页面是否发布。
代码
export const DEYAL_UPDATE_INTERVAL = 30 * 1000; // 30 秒
let initJsUrls: string[] = [];
// 获取 html
export async function fetchHtml(
url: string,
fetcher = window.fetch
): Promise {
try {
const res = await fetcher(url);
return res.text();
} catch (error) {
console.error(error);
return "";
}
}
// 提取 HTML 中所有 js 的地址
export function extractJsUrls(html: string): string[] {
const regex = /<script.*?src="(.*?)"/g;
const matches = [...html.matchAll(regex)];
return matches.map((match) => match[1]);
}
export async function needUpdate(targetUrl: string) {
const html = await fetchHtml(targetUrl);
let result = false;
if (html) {
const newJsUrls = extractJsUrls(html);
console.log(initJsUrls, newJsUrls);
if (initJsUrls.length != newJsUrls.length) {
result = true;
}
for (let i = 0; i < newjsurls.length i if newjsurlsi result='true;' break if initjsurls.length result='false;' initjsurls='newJsUrls;' return result export function autoupdate url: string duration: number='DEYAL_UPDATE_INTERVAL' settimeoutasync> {
const willUpdate = await needUpdate(url);
if (willUpdate) {
const result = confirm("检测到新版本,是否更新?");
if (result) {
window.location.reload();
}
}
autoUpdate(url, duration);
}, duration);
}