面试官最喜欢问的:前端怎么自动检测代码更新?

在前端开发中,我们通常会使用打包工具(如 Vite、Webpack)将 JS/CSS 等资源构建上线,并配合 CDN、浏览器缓存来加速访问。但问题也随之而来:

"我已经发布新版本了,怎么用户还看到旧界面?"

"为啥修复的 bug 还在?"

原因很简单:用户浏览器缓存了旧的静态资源,没有感知新版本的变更。

🎯 目标:前端页面如何自动检测打包更新并提示刷新

关键需求是:

  • 服务器发布了新版本,客户端能"感知"到。
  • 最好不依赖后端数据库或额外接口。
  • 弹窗或强制刷新,提示用户更新。

思考:为啥不直接加 hash?

其实我们打包时已经使用 [hash] 命名资源了,那为啥还要检测更新?

因为:

  • 浏览器对 HTML 本身不会缓存 bust;
  • 页面里写死了旧的 <script src="/main.abcd.js">,不会自动拉新版;
  • 用户长时间不刷新页面就不会拉取新 HTML,自然也没拉到新版 JS。

所以必须在 运行中的前端代码层面 进行更新感知。

方案一:轮询版本文件(最常用)

实现思路:

  1. 打包时生成一个版本文件(如 version.json 或注入 index.html 里的 __BUILD_VERSION__ 字段);
  2. 页面加载后,定时轮询该文件;
  3. 一旦检测到版本变更(比如哈希不同),提示用户刷新。

示例代码:

typescript 复制代码
const CURRENT_VERSION = __BUILD_VERSION__; // 构建时注入变量

setInterval(() => {
  fetch('/version.json?t=' + Date.now())
    .then(res => res.json())
    .then(({ version }) => {
      if (version !== CURRENT_VERSION) {
        alert('检测到新版本,点击确定刷新页面');
        window.location.reload(true);
      }
    });
}, 10000); // 每 10 秒轮询一次

或者使用文件指纹思路:

  1. 打包后生成一个 manifest 文件 (比如 asset-manifest.jsonmeta.json),里面记录资源及其 hash;

  2. 页面运行时轮询这个 manifest 文件;

  3. 如果发现文件名或 hash 有变,提示刷新页面。

在 Vite 中添加如下配置:

typescript 复制代码
// vite.config.ts
import { defineConfig } from 'vite'

export default defineConfig({
  build: {
    manifest: true, // 开启 manifest 生成
  }
})

构建后会生成 dist/manifest.json,类似这样:

typescript 复制代码
{
  "index.html": { "file": "index.html", "isEntry": true },
  "src/main.ts": { "file": "assets/main.abc123.js", "isEntry": true },
  "src/style.css": { "file": "assets/style.def456.css" }
}

前端代码(可封装成检测模块):

typescript 复制代码
let currentVersionHash = ''

function getHashFromManifest(manifest: any): string {
  // 自定义 hash 生成方式:可拼接所有文件路径,也可只取主入口
  return Object.values(manifest)
    .map((entry: any) => entry.file)
    .join('|')
}

async function checkForUpdate() {
  try {
    const res = await fetch(`/manifest.json?_t=${Date.now()}`)
    const manifest = await res.json()
    const newHash = getHashFromManifest(manifest)

    if (!currentVersionHash) {
      currentVersionHash = newHash
    } else if (currentVersionHash !== newHash) {
      console.log('🚨 发现新版本,准备刷新页面')
      alert('检测到新版本,点击确认刷新页面')
      window.location.reload(true)
    }
  } catch (err) {
    console.error('版本检查失败', err)
  }
}

setInterval(checkForUpdate, 10000) // 每 5 秒检查一次

💡manifest.json 中的文件路径含 hash,只要内容变,hash 就会变,就能准确识别版本是否更新。

优点:

  • 实现简单,支持所有现代浏览器;
  • 可手动控制提示逻辑,提升用户体验;
  • 和打包工具(Vite/Webpack)配合紧密。

缺点:

  • 本质上还是轮询,数据拉取有频率;
  • 如果用户挂着页面一整天,刷新前所有交互还是旧代码。

方案二:WebSocket(配合 CI/CD 或打包系统)

✅ 前提:

  • 服务端拥有 WebSocket 服务能力(如 Node.js + ws 模块);
  • 每次前端构建部署完成后,触发一次"更新通知"。

服务端(nodejs+ws模块):

js 复制代码
// ws-server.js
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });

const clients = new Set();

wss.on('connection', (ws) => {
  console.log('🚀 New client connected');
  clients.add(ws);

  ws.on('close', () => {
    clients.delete(ws);
  });
});

// 通知所有客户端刷新页面
function notifyClients() {
  for (let client of clients) {
    if (client.readyState === WebSocket.OPEN) {
      client.send(JSON.stringify({ type: 'update', message: 'new-version' }));
    }
  }
}

// 模拟触发更新(实际应在构建完成后调用)
setTimeout(() => {
  console.log('🎉 New version released, notifying clients...');
  notifyClients();
}, 10000); // 10 秒后触发

如果你有配套的部署平台或打包平台(如 Jenkins、Vercel、Netlify),可以在部署成功后广播一条"版本已更新"的消息。

客户端建立 WebSocket 连接,一旦收到推送,就提示刷新页面。

js 复制代码
if ('WebSocket' in window) {
  const ws = new WebSocket('ws://localhost:8080');

  ws.onopen = () => {
    console.log('[WS] Connected to update server');
  };

  ws.onmessage = (event) => {
    const data = JSON.parse(event.data);
    if (data.type === 'update') {
      console.log('[WS] New version detected');
      // 这里可以是弹窗提醒,或者直接刷新
      if (confirm('检测到新版本,是否立即刷新页面?')) {
        window.location.reload();
      }
    }
  };

  ws.onclose = () => {
    console.log('[WS] Connection closed');
  };

  ws.onerror = (err) => {
    console.error('[WS] Error:', err);
  };
}

可封装为插件或独立模块进行复用,比如 Vue 插件、React Hook、Vite 插件等。

优点:

  • 实时;
  • 可以配合更多更新逻辑(如强制下线);

缺点:

  • 成本高,依赖后端支持,对于检测更新的需求一般无需这么实时;
  • 不适合资源有限的小项目;

总结

前端页面检测更新并不是"有没有后端通知",而是我们主动地检测自己的版本是否已经被 CDN 或打包平台更新轮询 version.json 是最稳定、兼容性最强的方案; WebSocket 通知 是顶配方案,适合重型系统。

相关推荐
vvilkim17 分钟前
深入理解 TypeScript 中的 implements 和 extends:区别与应用场景
前端·javascript·typescript
GISer_Jing23 分钟前
前端算法实战:大小堆原理与应用详解(React中优先队列实现|求前K个最大数/高频元素)
前端·算法·react.js
振鹏Dong2 小时前
超大规模数据场景(思路)——面试高频算法题目
算法·面试
uhakadotcom2 小时前
Python 与 ClickHouse Connect 集成:基础知识和实践
算法·面试·github
uhakadotcom2 小时前
Python 量化计算入门:基础库和实用案例
后端·算法·面试
写代码的小王吧2 小时前
【安全】Web渗透测试(全流程)_渗透测试学习流程图
linux·前端·网络·学习·安全·网络安全·ssh
uhakadotcom2 小时前
使用Python获取Google Trends数据:2025年详细指南
后端·面试·github
uhakadotcom2 小时前
使用 Python 与 Google Cloud Bigtable 进行交互
后端·面试·github
uhakadotcom2 小时前
使用 Python 与 BigQuery 进行交互:基础知识与实践
算法·面试
uhakadotcom2 小时前
使用 Hadoop MapReduce 和 Bigtable 进行单词统计
算法·面试·github