Сервис-воркер остается в состоянии ожидания в Chrome - PullRequest
0 голосов
/ 04 августа 2020

Я работаю над СПА с Vue. Я хотел бы перейти на нового сервисного работника, когда пользователь переходит на определенную страницу c. Момент сохранения для refre sh, потому что представление пользователя уже меняется (шаблон, обсуждаемый в этом видео: https://youtu.be/cElAoxhQz6w)

У меня иногда (нечасто) возникает проблема сервис-воркер не активируется при вызове skipWaiting. Вызов выполнен правильно, и даже в Chrome я получаю ответ, что текущий сервис-воркер останавливается (см. Анимированный GIF), однако тот же сервис-воркер начинает работать снова вместо ожидающего.

self.skipWaiting () не работает в Service Worker

Я использую Vue. js, но я не зависим от плагина pwa для службы -рабочий. Я использую плагин webpack для workbox.

Я отредактировал приведенный ниже пример кода, минимальный код, вероятно, плохо отражал проблему

В основном. js:

let sw = await navigator.serviceWorker.register("/service-worker.js", {
  updateViaCache: "none",
});
let firstSw = false;

navigator.serviceWorker.addEventListener("controllerchange", () => {
  // no need to refresh when the first sw controls the page, we solve this with clientsClaim
  // this makes sure when multiple-tabs are open all refresh
  if (!firstSw) {
    window.location.reload();
  }
});

sw.onupdatefound = () => {
  const installingWorker = sw.installing;

  installingWorker.onstatechange = async () => {
    console.log("installing worker state-change: " + installingWorker.state);

    if (installingWorker.state === "installed") {
      if (navigator.serviceWorker.controller) {
        firstSw = false;
        // set the waiting service-worker in the store
        // so we can update it and refresh the page on navigation
        await store.dispatch("setWaitingSW", sw.waiting);
      } else {
        console.log("First sw available");
        firstSw = true;
      }
    }
  };
};

В роутере. js:

// after navigation to specific routes we check for a waiting service-worker.
router.afterEach(async (to) => {
  if (to.name == "specificpage") {
    let waitingSw = store.getters["getWaitingSW"];

    if (waitingSw) {
      waitingSw.postMessage("SKIP_WAITING");
      // clean the store, because we might have changed our data model
      await store.dispatch("cleanLocalForage");
    }
  }
});

В сервис-воркере. js:

self.addEventListener("message", event => {
  if (event.data === "SKIP_WAITING") {
    console.log("sw received skip waiting");
    self.skipWaiting();
  }
});

Ответы [ 2 ]

0 голосов
/ 11 августа 2020

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

0 голосов
/ 04 августа 2020

Я не уверен, что

let sw = await navigator.serviceWorker.register("/service-worker.js", {updateViaCache: "none"});

if (sw.waiting) {
  sw.waiting.postMessage("SKIP_WAITING");
}

- это тот код, который вам нужен в этом случае. Ваша проверка if (sw.waiting) оценивается только один раз, и только что зарегистрированный сервисный работник может все еще находиться в состоянии installing при ее оценке. В этом случае sw.waiting будет false -y во время первоначальной оценки, хотя через небольшой промежуток времени он может стать true -th.

Вместо этого я бы рекомендую следовать шаблону, подобному тому, который демонстрируется в этом рецепте , где вы явно слушаете, чтобы сервисный работник вводил waiting при регистрации. В этом примере используется библиотека workbox-window, чтобы скрыть некоторые детали.

Если вы не хотите использовать workbox-window, вы должны следовать этому руководству проверить, есть ли sw.installing устанавливается после регистрации; если это так, прослушайте событие statechange на sw.installing, чтобы определить, когда это 'installed'. Как только это произойдет, необходимо установить sw.waiting для вновь установленного сервис-воркера, и в этот момент вы можете postMessage() для него.

...