Как: ServiceWorker проверяет готовность к обновлению

Чего я пытаюсь достичь:

  • рендеринг страницы с загрузчиком / спиннером

  • если service-worker.js зарегистрирован и активен, затем проверьте наличие обновлений

    • если обновлений нет, то удали загрузчик
    • если updatefound и новая версия установлена, затем перезагрузите страницу
  • еще зарегистрироваться service-worker.js
    • когда updatefoundзначит новая установлена, удали загрузчик

я использую sw-precache модуль для меня, чтобы сгенерировать service-worker.js и следующий регистрационный код:

window.addEventListener('load', function() {

  // show loader
  addLoader();

  navigator.serviceWorker.register('service-worker.js')
    .then(function(swRegistration) {

      // react to changes in `service-worker.js`
      swRegistration.onupdatefound = function() {
        var installingWorker = swRegistration.installing;
        installingWorker.onstatechange = function() {
          if(installingWorker.state === 'installed' && navigator.serviceWorker.controller){

            // updated content installed
            window.location.reload();
          } else if (installingWorker.state === 'installed'){

            // new sw registered and content cached
            removeLoader();
          }
        };
      }

      if(swRegistration.active){
        // here I know that `service-worker.js` was already installed
        // but not sure it there are changes
        // If there are no changes it is the last thing I can check
        // AFAIK no events are fired afterwards
      }

    })
    .catch(function(e) {
      console.error('Error during service worker registration:', e);
    });
});

После прочтения спецификации становится ясно, что нет никаких обработчиков для чего-то вроде updatenotfound, Похоже serviceWorker.register проверяет, если service-worker.js изменилось внутренне, запустив get-newest-worker-алгоритма, но я не могу увидеть аналогичные методы, представленные через публичный API.

Я думаю, что мои варианты:

  • подождите пару секунд после активации регистрации работника службы, чтобы увидеть, onupdatefound уволен
  • запускать пользовательские события из service-worker.jsкод, если кеш не был обновлен

Любые другие предложения?


Редактировать:

Я придумал некоторый код, который решает эту проблему с помощьюpostMessage()между регистрацией ПО и клиентом ПО (как предложено @pate)

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


Редактировать:

Так что, похоже, я не могу реализовать то, что хочу, потому что:

  1. когда сервисный работник активен, вы не можете проверить наличие обновлений, оценивая некоторый код на SW - это все тот же кэшированный SW, никаких изменений там нет
  2. вам нужно ждатьonupdatefound, нет ничего другого, что будет уведомлять об изменениях в SW
  3. activationстарого ПО предшествуетonupdatefound
  4. если нет изменений, ничего не срабатывает послеactivation
  5. Регистрация SWupdate() незрелый, постоянно меняется, Starting with Chrome 46, update() returns a promise that resolves with 'undefined' if the operation completed successfully or there was no update
  6. установка тайм-аута для отсрочки рендеринга представления является неоптимальной, поскольку нет четкого ответа на то, как долго он должен быть установлен, это также зависит от размера SW

2 ответа

Другой ответ, предоставленный Фабио, не работает. Сценарий Service Worker не имеет доступа к DOM. Невозможно удалить что-либо из DOM или, например, манипулировать любыми данными, которые обрабатывают элементы DOM изнутри Service Worker. Этот скрипт выполняется отдельно без общего состояния.

Однако вы можете отправлять сообщения между действующим JS, работающим на странице, и сервисным работником. Я не уверен, что это лучший из возможных способов сделать то, о чем просит ОП, но его можно использовать для достижения этой цели.

  1. Зарегистрируйте обработчик сообщений на странице
  2. Отправьте сообщение с события активации или установки ПО на страницу
  3. Действуйте соответственно, когда сообщение получено на странице

Я сам сохранил номер версии ПО в переменной внутри ПО. Мой SW затем опубликовал этот номер версии на странице, и страница сохранила его в localStorage браузера. В следующий раз, когда страница загружается, SW публикует ее текущий номер версии на странице, и обработчик onmessage сравнивает его с текущим сохраненным номером версии. Если они не совпадают, то ПО было обновлено до некоторого номера версии, который был включен в сообщение. После этого я обновил localStorage копию номера версии и сделал то и это.

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

Я надеюсь, что смог объяснить мои мысли четко:)

Единственный способ, который возникает у меня в голове, - это нормально запустить загрузчик, а затем удалить его в сервис-работнике, в функции установки. Я попробую это сделать в вашем service-worker.js:

self.addEventListener('install', function(e) {
  console.log('[ServiceWorker] Install');
  e.waitUntil(
    caches.open(cacheName).then(function(cache) {
      console.log('[ServiceWorker] Caching app shell');
      return cache.addAll(filesToCache);
    }).then(function() {
        ***removeLoader();***
        return self.skipWaiting();
    })
  );
});
Другие вопросы по тегам