网站首页 > 技术文章 正文
背景
单页应用(Single Page Application,简称SPA)是一种现代Web应用程序架构,通过动态重载页面中的部分内容来提供更流畅和更响应式的用户体验。由于SPA在客户端(用户的浏览器)运行大量的JavaScript代码,并且与传统的多页应用不同,它不会每次操作都从服务器重新加载整个页面内容,因此在性能和用户体验上有显著优势。然而这种应用也存在一定弊端,譬如当服务端更新时(接口请求体和响应体结构发生变化),用户所使用的网页静态资源没有同步更新,就有可能导致报错。
前言
在传统的多页Web应用中,每次用户访问页面时,都会从服务器获取最新的页面和资源,因此版本更新相对简单,用户总是能获取到最新的版本。然而,SPA在首次加载后,前端的静态资源会缓存在浏览器内存中,且在整个使用过程中通常不会自动重新加载。这种特性意味着如果应用有新的版本发布,用户可能仍在使用旧版本,无法立即获得最新的功能、修复或安全更新。
怎么实现?
我们想实现这样一个效果,场景是:
攻城狮发版完成,客户端检测到有版本更新后给用户一个更新提示,让用户知道有新版本更新了
先来实现这个弹窗:
import { Modal } from 'antd'; function updateNotice() { Modal.confirm({ title: '更新提示', content: '检测到新版本,建议立即更新以确保平台正常使用。', okText: '确认更新', cancelText: '稍后更新', onOk: () => { window.location.reload(); }, }); }
方案一:比较构建文件的hash值
该方案需要webpack开启打包文件带上hash值,具体配置不在此处展开。
通过定期获取服务器的前端资源,匹配资源中的 <script> 标签,对比前后标签是否一致,来检测是否有新的版本发布。
// 存储当前脚本标签的哈希值集合 let scriptHashes = new Set(); let timer = undefined; /** * 从首页获取脚本标签的哈希值集合 * @returns {Promise<Set<string>>} 返回包含脚本标签的哈希值的集合 */ async function fetchScriptHashes() { // 获取首页HTML内容 const html = await fetch('/').then((res) => res.text()); // 正则表达式匹配所有<script>标签 const scriptRegex = /<script(?:\s+[^>]*)?>(.*?)<\/script\s*>/gi; // 获取匹配到的所有<script>标签内容 const scripts = html.match(scriptRegex) ?? []; // 将脚本标签内容存入集合并返回 return new Set(scripts); } /** * 比较当前脚本标签的哈希值集合与新获取的集合,检测是否有更新 */ async function compareScriptHashes() { // 获取新的脚本标签哈希值集合 const newScriptHashes = await fetchScriptHashes(); if (scriptHashes.size === 0) { // 初次运行时,存储当前脚本标签哈希值 scriptHashes = newScriptHashes; } else if ( scriptHashes.size !== newScriptHashes.size || ![...scriptHashes].every((hash) => newScriptHashes.has(hash)) ) { // 如果脚本标签数量或内容发生变化,则认为有更新
console.info('更新了', { oldScript: [...scriptHashes], newScript: [...newScriptHashes], }); // 清除定时器 clearInterval(timer); // 提示用户更新 updateNotice(); } else { // 没有更新 console.info('没更新', { oldScript: [...scriptHashes], }); } } // 每60秒检查一次是否有新的脚本标签更新 timer = setInterval(compareScriptHashes, 60000);
打印结果示例:
轮询效果: 有新版本发布时,服务器资源更新,才会返回新的资源给客户端; 资源未更新时,服务器返回304,不会返回资源,而是让客户端从本地缓存里获取,资源消耗相对较小。
方案二:利用HTTP协议的缓存机制,比较Etag或last-modified前后是否一致
本方案实现同方案一类似,但与方案一相比,方案二更直接地利用了 HTTP 协议提供的缓存控制机制,以确定页面是否发生了变化。
js
体验AI代码助手
代码解读
复制代码
let versionTag = null; // 版本标识 let timer = undefined; /** * 获取首页的 ETag 或 Last-Modified 值,作为当前版本标识 * @returns {Promise<string|null>} 返回 ETag 或 Last-Modified 值 */ const getVersionTag = async () => { const response = await fetch('/', { cache: 'no-cache', }); return response.headers.get('etag') || response.headers.get('last-modified'); }; /** * 比较当前的 ETag 或 Last-Modified 值与最新获取的值 */ const compareTag = async () => { const newVersionTag = await getVersionTag(); if (versionTag === null) { // 初次运行时,存储当前的 ETag 或 Last-Modified 值 versionTag = newVersionTag; } else if (versionTag !== newVersionTag) { // 如果 ETag 或 Last-Modified 发生变化,则认为有更新 console.info('更新了', { oldVersionTag: versionTag, newVersionTag: newVersionTag, }); // 清除定时器 clearInterval(timer); // 提示用户更新 updateNotice(); } else { // 没有更新 console.info('没更新', { oldVersionTag: versionTag, newVersionTag: newVersionTag, }); } }; // 每60秒检查一次是否有新的 ETag 或 Last-Modified 值 timer = setInterval(compareTag, 60000);
etag打印结果示例:
方案三:应用改造成PWA + service-worker方案
待补充...(篇幅过长,放到下篇博客再详谈)
总结
为了确保用户始终使用最新的版本并体验到最佳的功能和安全性,SPA应用需要实现版本检测和更新提示机制。当应用有新版本发布时,通过提示用户刷新页面或自动重新加载,以确保用户获取到最新的应用代码和资源。
作者:这里是阿栗
链接:
https://juejin.cn/post/7379157261426671657
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
猜你喜欢
- 2025-06-08 替换元素与页面可见性:提升前端体验的关键细节
- 2025-06-08 Web前端入门基础测试(web前端快速入门)
- 2024-09-29 软件测试和前端开发哪个更有前途?
- 2024-09-29 如何实现前端实时通信(WebSocket等)
- 2024-09-29 前端测试的反模式 前端反调试
- 2024-09-29 js基本搜索算法实现与170万条数据下的性能测试
- 2024-09-29 前端页面的性能测试 前端页面测试方法
- 2024-09-29 前端安全究竟该怎么做?从一个安全漏洞说起......
- 2024-09-29 前端精准测试实践 前端测试流程
- 2024-09-29 资深软件测试工程师:1分钟告诉你为何要进行前端代码测试?
你 发表评论:
欢迎- 501℃几个Oracle空值处理函数 oracle处理null值的函数
- 499℃Oracle分析函数之Lag和Lead()使用
- 495℃Oracle数据库的单、多行函数 oracle执行多个sql语句
- 483℃0497-如何将Kerberos的CDH6.1从Oracle JDK 1.8迁移至OpenJDK 1.8
- 478℃Oracle 12c PDB迁移(一) oracle迁移到oceanbase
- 474℃【数据统计分析】详解Oracle分组函数之CUBE
- 455℃Oracle有哪些常见的函数? oracle中常用的函数
- 452℃最佳实践 | 提效 47 倍,制造业生产 Oracle 迁移替换
- 最近发表
- 标签列表
-
- 前端设计模式 (75)
- 前端性能优化 (51)
- 前端模板 (66)
- 前端跨域 (52)
- 前端缓存 (63)
- 前端react (48)
- 前端aes加密 (58)
- 前端脚手架 (56)
- 前端md5加密 (54)
- 前端富文本编辑器 (47)
- 前端路由 (55)
- 前端数组 (65)
- 前端定时器 (47)
- Oracle RAC (73)
- oracle恢复 (76)
- oracle 删除表 (48)
- oracle 用户名 (74)
- oracle 工具 (55)
- oracle 内存 (50)
- oracle 导出表 (57)
- oracle 中文 (51)
- oracle链接 (47)
- oracle的函数 (57)
- 前端调试 (52)
- 前端登录页面 (48)
本文暂时没有评论,来添加一个吧(●'◡'●)