服务工作者`onupdatefound`未在移动设备上触发

时间:2017-07-18 12:42:02

标签: javascript android google-chrome service-worker workbox

贝娄是我注册我的服务工作者的方式:

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

我觉得用户体验非常糟糕,想到手机上的访客不知道新版网站正在等待......

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

编辑1:我已经找到了有关"浏览器兼容性"的详细信息。本网页的一部分:https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/onupdatefound。 Chrome for Android支持此功能似乎未知。

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

编辑2:回应杰夫,
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

关于你建议的工作箱微调,我还没有时间去挖掘,所以我在gulp文件中使用easy workbox-build。但我希望能够:)

// 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);
});

即使在登录Chrome,移动版或firefox时输出test,也只会在Chrome上投放更新消息

2 个答案:

答案 0 :(得分:1)

Android和Linux上的Chrome中的服务工作者实施应该没有任何差别,这会导致一个平台没有在服务工作者注册中暴露updatefound事件。 (MDN在这里不一定具有权威性。)

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

另外,您提到您正在使用Workbox - 如果是这种情况,您可以访问更高级的方法来检查更新的资源。 workbox-broadcast-cache-update插件(默认情况下,如果您正在使用workbox-sw的{​​{1}}方法启用)可以在更新特定缓存资源时发布,然后您可以侦听该消息在您的页面上使用广播频道API。这使您只能在最重要的资源发生变化时显示precache() - 就像HTML而不是不那么重要的资源,例如可能会预先缓存的随机图像。

答案 1 :(得分:1)

正如您所怀疑的那样,问题本身并不是来自服务工作者。

我从头开始尝试确定此问题的根源,逐个添加代码,直到不再显示任何事件。我明白了:这是因为一个昂贵的&#34; three.js动画中使用的循环。

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

关于它正在使用桌面版Chrome的令人困惑的事实,我猜它是因为它必须支持多线程...

再次感谢您的帮助:)