尽管sw.js没有改变,Service Worker正在“安装”每个页面重新加载

时间:2017-08-15 13:48:07

标签: javascript service-worker

我正在使用服务工作者来缓存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) {表示New or updated content is available的假设是否正确?
  • 我该如何调试问题?

1 个答案:

答案 0 :(得分:2)

服务人员有一个life cycle

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

注册服务工作者时,它是从服务器获取的,disk缓存中的生命周期取决于Web服务器发送的cache-control响应头。

如果可能,最佳做法是cache-control : no-store must-revalidatemax-age : 0

如果您忘记了,服务工作人员通常会在注册24小时后被视为stale,并且refetched和磁盘缓存已更新。

您可以通过在服务工作者上发布cache版本或更改服务工作者代码来进行手动升级。即使byte更改也会使浏览器view成为新服务工作者,并安装新的服务工作者。

然而,这并不意味着旧服务工作者被丢弃。任何用户关闭所有标签/ 导航都必须远离您的网站,浏览器必须丢弃旧服务工作者,并且< strong>激活新的。

您可以通过self.skipWaiting

中的install handler绕过此行为

那就是说,

开发时,您可以选择打开浏览器(铬) 在开发面板中,导航到application标签,然后选中

update on reload

这样做,立即丢弃旧服务工作者,无论您的服务工作者代码是否有变化。

关于你的问题:

  
      
  • 假设案例“已安装”是否正确:if(navigator.serviceWorker.controller){表示新内容或更新内容可用?
  •   

NO。这意味着,安装了新服务工作人员,例如sw-v1,并且当前waiting已激活。

  
      
  • 为什么“新的或更新的内容”案例经常发生?
  •   

你说,你正在使用sw-precache。既然,我自己没有使用它,我必须补充一个反问题

  • 是否已配置插件,以获取静态资产的更改,并自动触发service-worker中的代码更改或缓存突发?

如果是这样,那么,任何新版本的服务工作者在更改时都必须waiting而不是activating

等待阶段skipping的可能原因是,

  • 您的服务人员内self.skipWaiting事件中有install

注意以上情况属实,仅限

  • 您的内容发生了变化。 AND
  • 该更改会触发服务工作者更新

在这种情况下,您可能需要考虑注释掉self.skipWaiting语句。或者,也许你可以配置你的插件,不要跳过更新 - 这对你的内容很重要,你需要接听电话

代替您的资产已更改和/或触发更新这一事实,

其他(最可能的)原因必须是,

您在update on reload - &gt;下检查了application框您的开发控制台上的service workers标签。

取消选中该框,如果选中,则清除所有缓存,取消注册所有工作人员。之后,打开一个新选项卡并继续测试该行为。