Я все еще провожу эксперименты, чтобы освоить сервис-воркеры, и столкнулся с проблемой, вероятно, из-за отсутствия у меня опыта в JavaScript и сервис-воркерах.
Проблема возникает, когда я хочу, чтобы новый сервисный работник skipWaiting()
использовал postMessage()
. Если я показываю попап с кнопкой и привязываю туда вызов postMessage()
, то все работает. Если я вызову postMessage()
напрямую, это не сработает. Это состояние гонки, потому что ИНОГДА оно работает, но я не могу определить состояние гонки.
Кстати, вызов postMessage()
РАБОТАЕТ, сервисный работник регистрирует то, что должен, при получении сообщения:
// Listen to messages from clients.
self.addEventListener('message', event => {
switch(event.data) {
case 'skipWaiting': self.skipWaiting(); console.log('I skipped waiting... EXTRA');
break;
}
});
Вот код. Важный бит находится в условном выражении if (registration.waiting)
. Незакомментированный код работает, а закомментированный нет:
// Register service worker.
if ('serviceWorker' in navigator) {
// Helpers to show and hide the update toast.
let hideUpdateToast = () => {
document.getElementById('update_available').style.visibility = 'hidden';
};
let showUpdateToast = (serviceworker) => {
document.getElementById('update_available').style.visibility = 'visible';
document.getElementById('force_install').onclick = () => {
serviceworker.postMessage('skipWaiting');
hideUpdateToast();
};
document.getElementById('close').onclick = () => hideUpdateToast();
};
window.addEventListener('load', () => {
let refreshing = false;
navigator.serviceWorker.addEventListener('controllerchange', () => {
if (refreshing) return;
refreshing = true;
window.location.reload();
});
navigator.serviceWorker.register('/sw.js').then(registration => {
// A new service worker has been fetched, watch for state changes.
//
// This event is fired EVERY TIME a service worker is fetched and
// succesfully parsed and goes into 'installing' state. This
// happens, too, the very first time the page is visited, the very
// first time a service worker is fetched for this page, when the
// page doesn't have a controller, but in that case there's no new
// version available and the notification must not appear.
//
// So, if the page doesn't have a controller, no notification shown.
registration.addEventListener('updatefound', () => {
// return; // FIXME
registration.installing.onstatechange = function () { // No arrow function because 'this' is needed.
if (this.state == 'installed') {
if (!navigator.serviceWorker.controller) {
console.log('First install for this service worker.');
} else {
console.log('New service worker is ready to activate.');
showUpdateToast(this);
}
}
};
});
// If a service worker is in 'waiting' state, then maybe the user
// dismissed the notification when the service worker was in the
// 'installing' state or maybe the 'updatefound' event was fired
// before it could be listened, or something like that. Anyway, in
// that case the notification has to be shown again.
//
if (registration.waiting) {
console.log('New service worker is waiting.');
// showUpdateToast(registration.waiting);
// The above works, but this DOESN'T WORK.
registration.waiting.postMessage('skipWaiting');
}
}).catch(error => {
console.log('Service worker registration failed!');
console.log(error);
});
});
}
Почему непрямой вызов с помощью события кнопки onclick
работает, а вызов postMessage()
— нет?
Я совершенно в растерянности, и держу пари, что ответ прост, и я слишком слеп, чтобы увидеть его.
Заранее большое спасибо.
skipWaiting()
, не разрешается, функция по какой-то причине блокируется в webkit, если я не добавлю задержку, в то время как сообщение, на которое вы ссылаетесь, говорит о чем-то, что я уже знаю, вы можно наблюдать за событиями в обоих сервис-воркерах, и вы получите оба изменения состояния... В любом случае, спасибо, потому что источники Workbox довольно информативны, хотя это и не решает мою проблему - person Raúl Núñez de Arenas Coronado   schedule 04.02.2021self.skipWaiting()
сделайте это какsetTimeout(self.skipWaiting, 100)
. Возможно, вам придется настроить тайм-аут, и это хак, который мне не нравится, но он сработал. Сейчас я этим не пользуюсь, я просто вызываюself.skipWaiting()
непосредственно в обработчикеinstall
сервис-воркера. Брутально, но это работает для меня и до поры до времени. - person Raúl Núñez de Arenas Coronado   schedule 21.07.2021