每次页面重新加载时,Service Worker都会被“安装”,尽管sw.js文件没有更改。

7
我正在使用服务工作者缓存Web应用程序的JS和CSS文件。我主要使用了来自Google Chrome示例的代码,我添加的唯一内容是通知和倒计时,在“有新的或更新的内容可用”时刷新窗口。
Google示例:https://github.com/GoogleChrome/sw-precache/blob/5699e5d049235ef0f668e8e2aa3bf2646ba3872f/demo/app/js/service-worker-registration.js 然而,这种情况发生得太频繁,我不明白为什么。服务器上的文件绝对没有任何更改,但有时我仍然会看到通知并且窗口重新加载。
我原本期望只有当由服务工作者控制的任何文件实际更改时才会发生这种情况(它们都通过Webpack进行哈希处理,肯定在中间没有更改)。
以下是我在index.html中使用的代码:
/* eslint-env browser */
'use strict';
function reloadApp(delay) {
  var t = delay || 0;
  var message = 'New or updated content is available. Reloading app in {s} seconds';
  var getMessage = function() { return message.replace('{s}', t) }
  var div = document.createElement('div');
  div.id = 'update-notification';
  div.innerHTML = getMessage();
  document.body.appendChild(div);
  var intervalID = setInterval(function() {
    t = t - 1;
    if (t <= 0) {
      clearInterval(intervalID);
      window.location.reload();
    }
    else {
      div.innerHTML = getMessage();
    }
  }, 1000);
}
if ('serviceWorker' in navigator && window.location.protocol === 'https:') {
  navigator.serviceWorker.register('/service-worker.js').then(function(reg) {
    console.info('serviceWorker registered');
    reg.onupdatefound = function() {
      var installingWorker = reg.installing;
      installingWorker.onstatechange = function() {
        switch (installingWorker.state) {
          case 'installed':
            if (navigator.serviceWorker.controller) {
              reloadApp(5);
            } else {
              console.log('Content is now available offline!');
            }
            break;

          case 'redundant':
            console.error('The installing service worker became redundant.');
            break;
        }
      };
    };
  }).catch(function(e) {
    console.error('Error during service worker registration:', e);
  });
}

这是我所做的更改:

switch (installingWorker.state) {
  case 'installed':
    if (navigator.serviceWorker.controller) {
      // At this point, the old content will have been purged and the fresh content will
      // have been added to the cache.
      // It's the perfect time to display a "New content is available; please refresh."
      // message in the page's interface.
      console.log('New or updated content is available.');
    } else {

变成:

switch (installingWorker.state) {
  case 'installed':
    if (navigator.serviceWorker.controller) {
      reloadApp(5);

服务工作者本身是通过 sw-precache-webpack-plugin 生成的,哈希文件看起来像这样:

var precacheConfig = [["cms.CrudFactory.144344a2.js","6a65526f764f3caa4b8c6e0b84c1b31b"],["cms.routes.c20796b4.js","f8018476ceffa8b8f6ec00b297a6492d"],["common.cms-main.0f2db9ff.js","92017e838aff992e9f47f721cb07b6f0"],["common.licensing-main.8000b17d.js","0d43abd063567d5edaccdcf9c0e4c362"],["common.mediaplayer-main.314be5d2.js","2061501465a56e82d968d7998b9ac364"],["common.ordering-main.783e8605.js","0531c4a90a0fa9ea63fbe1f82e86f8c6"],["common.shared-main.0224b0ea.js","956ae4d2ddbddb09fb51804c09c83b22"],["common.stores-main.98246b60.js","cbdc46bc3abeac89f37e8f64b1737a22"],["component.App.284fec19.js","07f1923f1a0098bf9eba28fc7b307c18"],["component.AppToolbar.00e371de.js","9b542d4a85bdeece9d36ee4e389f6206"],["component.DevToolbar.652bf856.js","1744126e32774a93796146ac878ddd8e"],["component.Grid.4b964e52.js","755819ca2c7f911805e372401d638351"],["component.MediaPlayer.54db6e85.js","d0d8ae269665e810d1b997b473005f76"],["component.Search.05476f89.js","0cae8928aff533a6726dfaeb0661456a"],["data.country-list.d54f29a7.js","e27746418e02f75593a93b958a60807e"],["dev.sendSlackMessage.da8e22f4.js","ccb10829f18a727b79a5e8631bc4b2a2"],["index.html","02ff43eabc33c600e98785cffe7597d9"],["lib.gemini-scrollbar.df2fbf63.js","3941036bacb4a1432d22151ea7da073b"],["lib.isotope-horizontal.1604d974.js","6ac56d4296468c4428b5b5301a65938a"],["lib.isotope-packery.fabb73c3.js","808061641596e4b0ea2158b42d65915a"],["lib.react-color.265a6de0.js","f23f63d7e6934e381ffdc0405ecb449a"],["lib.react-date-picker.0a81fec3.js","778d1626645e439ad01e182ee589971a"],["lib.react-select.c768cf77.js","c8782991a161790ef2c9a2c7677da313"],["main.43e29bc6.js","fe6a6277acaa2a369ef235961be7bbcf"],["route.admin.CleanupPage.8b4bbf8e.js","8ab20412329e1ba4adc327713135be97"],["route.app.CmsPage.8a4303fb.js","0bf1506869db24bb9789c8a46449c8ad"],["route.app.CmsPageWrapper.accdebcc.js","c91e77aa8b518e1878761269deac22b6"],["route.app.ContactPage.75693d32.js","a530b00a5230a44897c2bf0aa9f402a8"],["route.app.PasswordResetExpiredDialog.65431bae.js","b5eef791dbd68edd4769bd6da022a857"],["route.app.SeriesDetailsPage.11a6989b.js","c52178b57767ae1bf94a9594cb32718e"],["route.cms.MetadataFormsPage.636188d2.js","e1e592b7e3dd82af774ac215524465c0"],["route.cms.PermissionsListPage.0e1e3075.js","9a3cc340a64238a1ab3ba1c0d483b7bd"],["route.cms.PermissionsPage.78a69f60.js","4b18e646715d6268e7aba3932f4e04a9"],["route.cms.SysconfigPage.f699b871.js","79bd1275213478f2ff1970e0b7341c49"],["styles.43e29bc620615f854714.css","b2e9e55e9ee2def2ae577ee1aaebda8f"],["styles.e0c12bb1c77e645e92d3.css","626778177949d72221e83b601c6c2c0f"],["translations.en.83fced0e.js","7e5509c23b5aafc1744a28a85c2950bb"],["translations.nl.4ae0b3bb.js","515ec7be7352a0c61e4aba99f0014a39"],["vendor.e0c12bb1.js","36ce9e0a59c7b4577b2ac4a637cb4238"]];
var cacheName = 'sw-precache-v3-nisv-client-' + (self.registration ? self.registration.scope : '');

问题:

  • 为什么“新内容或更新内容”情况经常会发生?
  • 假设case 'installed': if (navigator.serviceWorker.controller) {代表“有新内容或更新内容可用”,那这个假设是正确的吗?
  • 我该如何调试这个问题?

  1. 改变静态内容是否重新计算文件哈希值,并触发服务工作者更新?
  2. 您是否已选中“重新加载时更新”?
- Schrodinger's cat
1个回答

3

Service Worker(服务工作者)有一个生命周期

- registered
- installing
- installed
- waiting
- activated
- redundant

当您注册服务工作者时,它会从服务器获取,并且其在磁盘缓存中的寿命取决于您的 Web 服务器使用的缓存控制响应标头。最佳做法是尽可能使用“cache-control:no-store must-revalidate”以及“max-age:0”。如果忘记了这些设置,则服务工作者通常在注册后24小时被认为是陈旧的,并且会重新获取并更新磁盘缓存。您可以通过增加服务工作者的缓存版本或更改服务工作者代码来手动升级服务工作者。即使是一次字节更改,浏览器也会将服务工作者视为新服务工作者,并安装新服务工作者。但这并不意味着旧的服务工作者被丢弃。用户必须关闭所有选项卡/导航离开您的网站,以便浏览器丢弃旧的服务工作者并激活新的服务工作者。您可以通过在安装处理程序中使用“self.skipWaiting”来绕过此行为。在开发期间,您可以打开浏览器(Chromium)的开发面板,导航到“应用程序”选项卡,并选中“刷新时更新”复选框。这样做会立即丢弃旧的服务工作者,而不管您的服务工作者代码是否有更改。关于您的问题:当 case 'installed': if (navigator.serviceWorker.controller) { 时,假设正确的是新内容或已更新的内容可用吗?不是。这意味着新服务工作者(例如sw-v1)已安装,并且当前正在等待激活。为什么“新内容或已更新内容”情况经常发生?您说您正在使用“sw-precache”。由于我自己没有使用过它,因此我必须补充一个问题:插件是否已配置为获取静态资产的更改,并自动触发代码更改或缓存增量在您的服务工作者中?如果是这样,则任何服务工作者的新版本必须仅处于等待状态,而不是在更改时激活。跳过等待阶段的可能原因是:
  • 你的service worker中在install事件中有一个self.skipWaiting。

注意:仅当以下条件满足时才为真:

  • 您的内容发生了更改。并且
  • 该更改触发了service worker更新

在这种情况下,您可能需要考虑注释掉self.skipWaiting语句。或者,也许您可以配置插件,在更新时不跳过 - 这取决于您的内容,并且您需要做出决策

鉴于您的资源发生了更改和/或触发了更新,

另一个(最有可能的)原因是,

您在dev console的应用程序->服务工作者选项卡下勾选了“重新加载更新”框。

如果已经勾选,请取消选择该框,然后清除所有缓存,注销所有工作人员。之后,打开一个新标签继续测试行为。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接