3

Bellow 是我如何注册我的 serviceworker :

if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    function updateOnlineStatus() {
      SnackBar.show({
        text: navigator.onLine ? onlineMsg : offlineMsg,
        backgroundColor: '#000000',
        actionText: close,
        actionTextColor: '#d2de2f',
        customClass: 'custom-snackbar',
      });
    }
    window.addEventListener('online', updateOnlineStatus);
    window.addEventListener('offline', updateOnlineStatus);
    navigator.serviceWorker.register('sw.js').then((reg) => {
      reg.onupdatefound = () => {
        const installingWorker = reg.installing;
        installingWorker.onstatechange = () => {
          switch (installingWorker.state) {
            case 'installed':
              if (navigator.serviceWorker.controller) {
                SnackBar.show({
                  text: refreshMsg,
                  backgroundColor: '#000000',
                  actionText: refresh,
                  actionTextColor: '#d2de2f',
                  onActionClick: () => { location.reload(); },
                  customClass: 'custom-snackbar',
                });
              } else {
                console.info(availableMsg);
              }
              break;
            case 'redundant':
              console.info(redundantMsg);
              break;
            default:
              break;
          }
        };
      };
    }).catch((e) => {
      console.error(errorMsg, e);
    });
  });
}

这个 service-worker 是在 Workbox 构建期间生成的。

我有点担心,因为这些通知显示在我的电脑(ubuntu + chrome 59.0.3071.115)上,但从来没有显示在我的手机上(android 6.0.1+ chrome 59.0.3071.125

使用远程调试功能进行分析后,我的手机似乎onupdatefound从未触发过。

我对 UX 感觉非常糟糕,考虑到移动设备上的访问者不知道新版本的网站正在等待中......

任何建议或意见将不胜感激


编辑 1:我在此网页的“浏览器兼容性”部分找到了更多详细信息:https ://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/onupdatefound 。看起来 Android 版 Chrome 是否支持此功能尚不清楚。

onupdatefound当浏览器不支持事件时,你们有一种后备/解决方法吗?


编辑 2:作为对 Jeff 的回应,
sw.js标头在.htaccess文件中进行管理:

<Files sw.js>
  Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
  Header set Pragma "no-cache"
  Header set Expires "Wed, 11 Jan 1984 05:00:00 GMT"
</Files>

产生:

accept-ranges: bytes
cache-control: max-age=0, no-cache, no-store, must-revalidate
content-encoding: br
content-language: fr-FR
content-length: 1636
content-type: application/javascript; charset=utf-8
date: Fri, 21 Jul 2017 13:04:06 GMT
expires: Wed, 11 Jan 1984 05:00:00 GMT
last-modified: Tue, 18 Jul 2017 02:58:30 GMT
pragma: no-cache

关于您建议的工作箱微调,我还没有时间深入研究,所以我workbox-build在 gulp 文件中使用了 easy 。但我希望会:)

// Service Worker generation
gulp.task('bundle-sw', gulp.series('generate-sitemap', () => {
  return wbBuild.generateSW({
    globDirectory: gulpOutputDir,
    swDest: `${gulpOutputDir}/sw.js`,
    globPatterns: ['**/*.{html,png,xml,css,ico,txt,json,svg,js,map,gif,jpeg,jpg,bmp,cur,webp,woff2}'],
    skipWaiting: true,
    clientsClaim: true,
  })
  .then(() => {
    console.warn('Service worker generated.');
  })
  .catch((err) => {
    console.error(`[ERROR] This happened: ${err}`);
  });
}));

你认为这可能是由skipWaiting: true?


编辑 3:尝试使用 BroadcastChannel

navigator.serviceWorker.register('/sw.js').then((reg) => {
  console.log('test');
  const updateChannel = new BroadcastChannel('precache-updates');
  updateChannel.addEventListener('message', event => {
    console.log(`Cache updated: ${event.data.payload.updatedUrl}`);
  });
}).catch((e) => {
  console.error(errorMsg, e);
});

即使test在 Chrome、mobile 或 firefox 的 log 中输出,也只会在 Chrome 上抛出更新消息

4

2 回答 2

2

正如您所怀疑的,问题根本不是来自 Service Worker 本身。

我从头开始,试图找出这个问题的根源,逐段添加代码,直到不再暴露任何事件。我想通了:这是因为three.js动画中使用了“昂贵”的循环。

将这段代码放入工作人员后,我的页面现在能够在移动设备或 Firefox 上捕获这些事件,并且用户的通知工作正常!

关于它在桌面版 Chrome 上工作的令人困惑的事实,我想这是因为它必须支持多线程......

再次感谢你的帮助 :)

于 2017-08-09T02:27:21.730 回答
1

在 Android 和 Linux 上的 Chrome 中的服务工作者实现不应该有任何差异,这将说明一个平台没有updatefound在服务工作者注册上公开事件。(这里 MDN 不一定是权威的。)

过去,每当我调试这种不可预测的更新时,都是由于与 HTTP 缓存和sw.js脚本的交互。你能检查一下Cache-Control你服务时使用的标题sw.js吗?

此外,您提到您正在使用 Workbox — 如果是这种情况,您可以访问更高级的方法来检查更新的资源。该workbox-broadcast-cache-update插件(如果您使用workbox-sw'sprecache()方法则默认启用)可以宣布特定缓存资源何时更新,然后您可以使用广播频道 API 在页面上收听该消息。这允许您仅SnackBar在最重要的资源(如 HTML)发生更改时显示您的资源,而不是不太重要的资源(如可能预缓存的随机图像)。

于 2017-07-20T20:09:55.840 回答