App Shell缓存后页面内容不更新怎么办?

Mc.晓萌 阅读 22

我按照教程做了App Shell结构的PWA,但更新了HTML内容后,用户访问还是显示旧页面。明明已经设置了service worker的版本号,清除浏览器缓存也没用。


<!-- manifest.json -->
{
  "name": "MyApp",
  "short_name": "MyApp",
  "start_url": "./index.html",
  "display": "standalone"
}

<!-- service-worker.js -->
const CACHE_NAME = 'app-cache-v1';
self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open(CACHE_NAME).then(cache => {
      return cache.addAll([
        './index.html',
        './styles.css',
        './script.js'
      ]);
    })
  );
});

我尝试过修改版本号到v2重新部署,但用户手机里还是显示旧的HTML结构。用Lighthouse测试说资源已正确缓存,但页面内容就是不更新…

我来解答 赞 4 收藏
二维码
手机扫码查看
2 条解答
书生シ诗辰
这个问题我之前也碰到过,挺让人头疼的。其实核心原因是service worker的缓存策略和更新机制没处理好。

你虽然改了版本号,但用户那边的老service worker可能还在运行,它会继续使用之前的缓存。比较靠谱的做法是监听activate事件,并在install时清理旧缓存。

给你一个改进后的代码示例:


const CACHE_NAME = 'app-cache-v2';
const OLD_CACHE = 'app-cache-v1';

self.addEventListener('install', (event) => {
// 跳过等待,立即接管新版本
self.skipWaiting();
event.waitUntil(
caches.open(CACHE_NAME).then(cache => {
return cache.addAll([
'./index.html',
'./styles.css',
'./script.js'
]);
})
);
});

self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.map(cache => {
if (cache !== CACHE_NAME && cache === OLD_CACHE) {
return caches.delete(cache);
}
})
);
})
);
});


另外要注意,客户端这边最好在注册service worker时加上更新检测:


if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('./service-worker.js').then(registration => {
registration.update(); // 强制检查更新
});
}


最后提醒一下,改完后记得把版本号改成v3,不然还是可能命中之前的缓存。还有就是开发阶段可以在Chrome DevTools的Application面板里手动unregister掉现有的service worker,方便调试。

对了,别忘了在manifest.json里加个version字段,虽然不是必须的,但有助于跟踪版本:
"version": "1.0.1"

这样一套组合拳下来,基本就能解决缓存更新的问题了。
点赞
2026-02-15 16:14
迷人的庆晨
问题出在缓存更新策略上。你改了版本号,但旧的service worker还在运行,新的没生效。浏览器会优先使用已安装的worker,直到它被激活或卸载。

改一下就行,给你的service worker加个激活逻辑,清理旧缓存:

const CACHE_NAME = 'app-cache-v2';

self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME).then(cache => {
return cache.addAll([
'./index.html',
'./styles.css',
'./script.js'
]);
})
);
});

// 加这个
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.map(cache => {
if (cache !== CACHE_NAME) {
return caches.delete(cache);
}
})
);
})
);
});


还有个简单粗暴的办法,在index.html引用文件时加个时间戳参数:

<link rel="stylesheet" href="./styles.css?v=20231015">
<script src="./script.js?v=20231015"></script>


记得把CACHE_NAME改成新版本号,比如'app-cache-v2'。每次更新静态资源时记得改版本号或者时间戳。

最后提醒下,开发时最好打开Chrome devtools的“Update on reload”选项,这样能实时看到修改效果,不用每次都手动清除缓存。
点赞 1
2026-02-14 16:07