Chrome中navigator.serviceWorker.ready Promise始终无法resolve,Edge/Opera正常运行、Firefox报错
看起来你碰到了一个挺棘手的Service Worker兼容性问题,我之前也遇到过类似的情况,先帮你梳理下可能的原因和解决思路:
先排查Service Worker的核心状态
Chrome里navigator.serviceWorker.ready迟迟不resolve,大概率是你的Service Worker没走完安装→激活的完整流程。你可以打开Chrome DevTools的Application标签页,找到Service Workers面板,看看SW的状态:
- 如果一直卡在
installing:说明安装阶段出了问题,最常见的就是cache.addAll里的资源加载失败(比如404、跨域或加载超时) - 如果停在
waiting:说明新SW安装好了,但旧SW还在控制页面,没被替换掉
检查Service Worker代码里的潜在坑
看你的SW代码,有几个容易踩的点:
cache.addAll的错误捕获不完整
你在install事件里加了try/catch,但e.waitUntil里的cache.addAll是异步操作,一旦某个资源加载失败,这个Promise会直接reject,而外层的try/catch捕获不到这个异步错误,会导致SW安装失败。可以改成async/await写法,把整个逻辑包在try里:
self.addEventListener('install', async (e) => { try { const cache = await caches.open(CACHE_NAME); await cache.addAll([ '/Vanilla/test_sg9.html', '/Vanilla/Scales.png', // 其他资源... ]); await self.skipWaiting(); console.log("SW安装完成"); } catch(err) { console.error('SW安装失败:', err); } console.log("Leaving install"); })
self.skipWaiting()的执行时机
你现在是在cache.addAll的then回调里调用skipWaiting(),如果cache.addAll失败,这步就不会执行,新SW会一直处于waiting状态,无法激活,自然ready就不会触发。用async/await写法能更清晰地控制执行顺序。activate事件里的多个
e.waitUntil
你在activate事件里调用了两次e.waitUntil,这可能导致逻辑冲突,建议把两个Promise合并成一个:
self.addEventListener('activate', (e) => { e.waitUntil( Promise.all([ // 清理旧缓存 caches.keys().then((keyList) => { return Promise.all(keyList.map((key) => { if (key !== CACHE_NAME) { console.log('Removing cache', key); return caches.delete(key); } })) }), // 立即控制所有打开的页面 self.clients.claim() ]) ) })
关于Firefox的异常
Firefox对module类型的Service Worker处理逻辑更严格,你可以打开Firefox的控制台看具体错误信息,大概率是模块导入(比如/Vanilla/config.js)或资源加载的问题。
临时兜底方案(如果暂时无法修复激活问题)
你提到的SO workaround确实可以作为临时方案,通过监听controllerchange事件来兜底:
if ("serviceWorker" in navigator) { const reg = await navigator.serviceWorker.register('/Vanilla/CacheManager.js', { scope: '/Vanilla/', type: 'module' }) .catch(err => console.log('SW Registration failed with ' + err)); // 检查是否已有激活的SW if (navigator.serviceWorker.controller) { cacheManagerSubscription = await navigator.serviceWorker.ready; } else { // 等待controller变化 await new Promise(resolve => { navigator.serviceWorker.addEventListener('controllerchange', resolve); }); cacheManagerSubscription = await navigator.serviceWorker.ready; } }
不过这只是权宜之计,还是建议从根源上解决SW的安装激活问题。
额外小建议
- 每次修改SW代码后,在Chrome DevTools的Service Workers面板勾选
Update on reload,强制刷新SW - 检查所有缓存资源的路径是否正确,服务器环境下可能区分大小写
- 确认
/Vanilla/config.js能正常加载,module类型的SW导入失败会直接导致SW无法运行
备注:内容来源于stack exchange,提问作者McMurphy
相关产品推荐
相关产品推荐

