Service Worker skipWaiting не может активировать ожидающее в данный момент ПО

Описание:

Мы используем sw precache для кэширования сценариев заранее, поэтому для обновления сценариев мы даем опцию перезагрузки, для этого мы слушаем рабочее сообщение, чтобы пропустить ожидание нового установленного сервисного работника по неизвестной причине, мы не получаем правильно

скрипт импорта

// GETTING OLD SW reference (self) and NOT getting newly installed SW reference

self.addEventListener('message', function(event) {
    *// not working*
    self.skipWaiting();
});



// But if we put skipWaiting() in 'install' listener 
// it is getting correct new SW reference and working correctly

self.addEventListener('install', function(event) {
    // self.skipWaiting();
});

Регистрация ПО

if('serviceWorker' in window.navigator) {
      window.addEventListener('load', function() {
        window.navigator.serviceWorker.register("/serviceWorker.js").then(function(registration) {
          console.log("ServiceWorker registration successful with scope: ", registration);
          registration.onupdatefound = function() {
            console.log('NEW WILD WORKER HAS SPAWNED.!', registration);
            var installedWorker = registration.installing;
            installedWorker.onstatechange = function() {
              if (installedWorker.state === 'installed') {
                if (navigator.serviceWorker.controller) {
                  console.log('Updated content is available RELOAD!', navigator.serviceWorker.controller);
                  var el = document.getElementById('feature');
                  el.style['display'] = 'block';
                }
              }
            }
          }
        }).catch(function(error) {
          console.error("ServiceWorker registration failed: ", error);
        });
      });
      window.navigator.serviceWorker.addEventListener('controllerchange', function() {
        console.log('SERVICE WORKER UPDATED');
      });
    }

конфигурация веб-пакета

new SWPrecacheWebpackPlugin({
        cacheId: 'pwa',
        filename: 'serviceWorker.js',
        staticFileGlobsIgnorePatterns: [/\.map$/, /\.json$/, /_nch\.[0-9a-z]+\.[js, css]+/g, /webpackManifest\.[0-9a-z]+\.js/g, /.DS_Store\.[0-9a-z]+/g],
        importScripts: ['offline/offline.1a2b3c4df1.js'],
        dontCacheBustUrlsMatching: /./,
        minify: false,
        skipWaiting: false,
        runtimeCaching: [ {
          urlPattern: /_nch\.[0-9a-z]+\.[js, css]+/g,
          handler: 'fastest',
          options: {
            cache: {
              name: 'jd-internal-script',
              maxEntries: 10,
            },
          },
        }, {
          urlPattern: /webpackManifest\.[0-9a-z]+\.js/g,
          handler: 'networkFirst',
          options: {
            cache: {
              name: 'jd-root-doc',
            },
          },
        }],
      }),

person Anurag Singh    schedule 21.09.2017    source источник


Ответы (2)


Лучшая документация по skipWaiting() находится по адресу https://developers.google.com/web/fundamentals/instant-and-offline/service-worker/lifecycle#skip_the_waiting_phase

Вы можете либо вызвать его безоговорочно в обработчике install, либо следовать модели, которую вы, кажется, делаете, то есть прослушивать событие message и вызывать skipWaiting() условно.

Если вы идете по условному маршруту, вам следует изменить код своей клиентской страницы, чтобы правильно определять, когда регистрируемый вами сервис-воркер переходит в состояние waiting, и предоставлять пользователю возможность взаимодействия со страницей таким образом, чтобы это приводило к соответствующему postMessage() сообщить сервисному работнику skipWaiting(). Основываясь на том, что вы говорите, вы пробовали это, но похоже, что вы отправляете сообщение не тому экземпляру работника службы.

Вот как должен выглядеть код вашей страницы:

// On your page:
if ('serviceWorker' in navigator) {
  window.addEventListener('load', function() {
    navigator.serviceWorker.register('service-worker.js').then(function(reg) {
      reg.onupdatefound = function() {
        var newSW = reg.installing;
        newSW.onstatechange = function() {
          if (newSW.state === 'waiting') {
            // This assumes there's a button with id='skip-waiting-button' that
            // users should click to get the new SW to activate immediately.
            var button = document.querySelector('#skip-waiting-button');
            button.addEventListener('click', function() {
              newSW.postMessage('skipWaiting');
            });
            // Assume that 'display' is 'none' initially.
            button.style.display = 'inline';
          }
          // Handle whatever other SW states you care about, like 'active'.
        };
      };
    })
  });
}

// In your service worker:
self.addEventListener('message', event => {
  if (event.data === 'skipWaiting') {
    self.skipWaiting();
  }
});
person Jeff Posnick    schedule 25.09.2017
comment
Спасибо за эту работу. Могу ли я перейти на Workbox для реализации сервис-воркеров, потому что в настоящее время я использую sw-precache и sw-toolbox для достижения этой цели. Поэтому было бы полезно, если бы вы могли предоставить некоторые ресурсы, касающиеся реализации Workbox с помощью webpack. - person Anurag Singh; 26.09.2017
comment
installWorker.onstatechange в этом случае мы получаем ошибку installWorker is undefined, поэтому вместо него нужно использовать newSW? - person Anurag Singh; 26.09.2017
comment
newSW.state = 'ожидание' это не удовлетворяет вместо этого мы получаем newSW.state = 'установлено'. Следовательно, мы не можем использовать состояние ожидания. - person Anurag Singh; 26.09.2017
comment
Да, код должен был быть newSW. Я обновил его. Не должно быть ситуации, в которой вновь зарегистрированное ПО остается на неопределенный срок в состоянии installed. Он должен либо перейти на waiting (если есть другой SW и вы не звоните skipWaiting() или active (если нет другого SW, или если вы вызываете skipWaiting()). - person Jeff Posnick; 26.09.2017
comment
Он в установленном состоянии. Состояние меняется на ожидание, если я делаю обновление, тогда в newSW.onstatechange = () => { ... .. } наблюдается только состояние ожидания. Можете ли вы подсказать, что может пойти не так, чтобы зарегистрированное ПО постоянно находилось в установленном состоянии. Хотя в консоли браузера новое ПО находится в состоянии ожидания. - person Anurag Singh; 26.09.2017
comment
Состояние «ожидание» невозможно найти в определениях машинописного текста: type ServiceWorkerState = "installing" | "installed" | "activating" | "activated" | "redundant"; Оно вообще существует? - person Alex C; 05.02.2019
comment
@AlexC, ты понял это? - person itaintme; 29.05.2019
comment
то же самое, я также не получаю newSW.state как «ожидание», все, что я получаю, это «установка» изменения состояния, вот и все. - person Nishant Desai; 04.08.2019
comment
Как указывает @AlexC, состояние ожидания не соответствует странице, на которую ссылается Джефф: developers.google.com/web/fundamentals/primers/service-workers/ - person REJH; 21.03.2020
comment
@JeffPosnick Я сталкиваюсь с множеством проблем, чтобы убедиться, что у всех пользователей есть последняя версия приложения как можно скорее. Я использую skipWaiting() при обратном вызове onstatechange installWorker, но время от времени skipWaiting() не срабатывает! Как я могу быть уверен, что это не повторится? - person Mehrnoosh; 16.07.2021

Итак, вот что я думаю... Ваш новый сервис-воркер все еще ждет... следовательно, прослушиватель событий все еще находится на вашем старом сервис-воркере... любые сообщения, которые вы отправляете, все равно будут перехвачены старым sw (поскольку новый ждет) .

Если ваш единственный случай - заставить новый sw работать, вы можете просто обновить свою страницу вместо отправки сообщения.

person prateekbh    schedule 22.09.2017
comment
Но если я это сделаю, то первая стратегия кэширования не будет работать, потому что webpackManifest и документ кэшируются во время выполнения из-за динамического документа, созданного экспрессом. В этом случае я должен переключиться на первую стратегию сети. - person Anurag Singh; 22.09.2017
comment
Мы говорим здесь о пакетах или API или о чем именно? - person prateekbh; 22.09.2017
comment
Речь идет только о пакетах. Когда клиент делает запрос на документ, сервер отправляет документ, затем, когда документ анализируется, сервисный работник загружается, сервисный работник устанавливается и активируется. После этого он предварительно кэширует этот ресурс (поставщик и т. д.). Теперь, если я внесу некоторые изменения в мой скрипт и разверну новую сборку. Затем, когда в следующий раз клиент попадет на сервер, он обнаружит изменение в файле сервисного работника, который будет загружен и установлен, и перейдет в состояние ожидания, поэтому теперь я отображаю всплывающее сообщение &&, когда пользователь щелкает, я вызываю self.skipwaiting, а затем перезагружаю страницу. - person Anurag Singh; 24.09.2017
comment
что произойдет, если вы не вызовете skipWaiting и просто перезагрузите страницу? - person prateekbh; 25.09.2017
comment
если я перезагружу страницу, все еще старый сервисный работник контролирует страницу, пока я не перейду на другой URL-адрес или не сделаю жесткое обновление, тогда только новый сервисный работник возьмет на себя управление страницей. - person Anurag Singh; 25.09.2017