You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Safari浏览器反复提示未变更Service Worker更新的问题

Vue PWA在Safari中路由切换反复触发Service Worker更新提示的问题

我基于VueJS构建了一个PWA应用,使用register-service-worker管理Service Worker,配置了路由切换时手动检查更新,若存在更新则向用户显示刷新提示。但在MacOS和iOS的Safari浏览器中遇到异常:尽管应用已显示最新内容,每次路由切换仍会触发“有可用更新”的提示,刷新操作也无法解决该问题,本地Service Worker似乎并未完成更新。

相关代码

路由切换时检查更新的代码

router.beforeEach((to, from, next) => {
    navigator.serviceWorker.getRegistration(`${process.env.BASE_URL}service-worker.js`).then(reg => {
        // check for updates to the service working on change of route
        reg.update();
    });
});

registerServiceWorker.js文件

/* eslint-disable no-console */
import { register } from 'register-service-worker'

if (process.env.NODE_ENV === 'production') {
  register(`${process.env.BASE_URL}service-worker.js`, {
    ready () {
      console.log(
        'App is being served from cache by a service worker.\n' 
      )
    },
    registered () {
      console.log('Service worker has been registered.')
    },
    cached () {
      console.log('Content has been cached for offline use.')
    },
    updatefound () {
      console.log('New content is downloading.')
    },
    updated (registration) {
        console.log('New content is available; please refresh.')
        document.dispatchEvent(
            new CustomEvent('swUpdated', { detail: registration })
        )
    },
    offline () {
      console.log('No internet connection found. App is running in offline mode.')
    },
    error (error) {
      console.error('Error during service worker registration:', error)
    }
  })
}

Vue应用监听更新事件的代码

...
document.addEventListener('swUpdated', this.updateAvailable, { once: true })
...
updateAvailable(event) {
   this.registration = event.detail
   this.showReloadDialog = true
},
...

问题原因分析

Safari对Service Worker的实现与Chrome等浏览器存在差异,主要问题点包括:

  1. 未处理等待激活的Service Worker:新SW安装后,Safari不会自动激活,导致等待状态的SW一直存在,每次调用reg.update()都会触发updated钩子。
  2. 注册路径不一致:getRegistration传入的路径与register方法的路径可能存在解析差异,导致获取到错误的注册实例。
  3. 事件监听逻辑缺陷:{ once: true }在Safari中可能未正确生效,或者未在更新完成后清除等待状态的SW,导致反复触发提示。

解决方案

1. 统一Service Worker注册路径

避免手动拼接路径,直接调用getRegistration()获取当前注册实例,确保与register方法的路径一致:

router.beforeEach((to, from, next) => {
  // 省略路径参数,自动获取当前域名下的SW注册实例
  navigator.serviceWorker.getRegistration().then(reg => {
    if (reg) { // 确保注册实例存在再执行更新检查
      reg.update();
    }
  });
  next(); // 必须调用next(),否则路由会被阻塞
});

2. 处理等待激活的Service Worker

在updated钩子中仅当存在等待激活的SW时才触发提示,并在用户确认后手动激活新SW:

修改registerServiceWorker.js的updated钩子

updated (registration) {
  // 仅当存在等待激活的SW时才提示更新
  if (registration.waiting) {
    console.log('New content is available; please refresh.');
    document.dispatchEvent(
      new CustomEvent('swUpdated', { detail: registration })
    );
  }
}

在Vue组件中添加激活逻辑

updateAvailable(event) {
  this.registration = event.detail;
  this.showReloadDialog = true;
},
// 刷新按钮点击事件
handleReload() {
  if (this.registration.waiting) {
    // 向等待的SW发送激活指令
    this.registration.waiting.postMessage({ type: 'SKIP_WAITING' });
    // 监听SW激活完成后刷新页面
    navigator.serviceWorker.addEventListener('controllerchange', () => {
      window.location.reload();
    });
  }
}

自定义Service Worker添加消息监听

如果使用Vue CLI生成的默认SW,需要创建自定义service-worker.js文件并在vue.config.js中配置,添加消息监听:

// service-worker.js
self.addEventListener('message', (event) => {
  if (event.data?.type === 'SKIP_WAITING') {
    self.skipWaiting();
  }
});

3. 限制更新检查频率

避免每次路由切换都触发检查,设置冷却时间(比如1分钟):

let lastUpdateCheck = 0;
router.beforeEach((to, from, next) => {
  const now = Date.now();
  // 1分钟内仅检查一次更新
  if (now - lastUpdateCheck > 60000) {
    navigator.serviceWorker.getRegistration().then(reg => {
      reg?.update();
    });
    lastUpdateCheck = now;
  }
  next();
});

4. 优化事件监听逻辑

手动管理事件监听,避免重复触发:

mounted() {
  const handleUpdate = (event) => {
    this.updateAvailable(event);
    // 处理后移除监听
    document.removeEventListener('swUpdated', handleUpdate);
  };
  document.addEventListener('swUpdated', handleUpdate);
  // 保存引用以便销毁时移除
  this.handleUpdate = handleUpdate;
},
beforeUnmount() {
  document.removeEventListener('swUpdated', this.handleUpdate);
}

内容的提问来源于stack exchange,提问作者David

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 02:50:29