Ответ 1
Рабочие службы — веб-работники вообще — не имеют прямого доступа к DOM. Вместо этого, рабочий должен опубликовать информацию в основной поток, а код в основном потоке обновит DOM, если это необходимо. Замещающая модель для JavaScript в браузерах заключается в том, что существует только один основной поток пользовательского интерфейса (по умолчанию используется ваш код на странице), который может получить доступ к DOM. Остальные отгорожены от него.
Эта страница и эта страница говорят о обмене сообщениями между сервисными работниками и клиентами. Вот действительно простой пример:
Script на странице загрузки сервисного работника:
(function() {
"use strict";
if (!navigator.serviceWorker || !navigator.serviceWorker.register) {
console.log("This browser doesn't support service workers");
return;
}
// Listen to messages from service workers.
navigator.serviceWorker.addEventListener('message', function(event) {
console.log("Got reply from service worker: " + event.data);
});
// Are we being controlled?
if (navigator.serviceWorker.controller) {
// Yes, send our controller a message.
console.log("Sending 'hi' to controller");
navigator.serviceWorker.controller.postMessage("hi");
} else {
// No, register a service worker to control pages like us.
// Note that it won't control this instance of this page, it only takes effect
// for pages in its scope loaded *after* it installed.
navigator.serviceWorker.register("service-worker.js")
.then(function(registration) {
console.log("Service worker registered, scope: " + registration.scope);
console.log("Refresh the page to talk to it.");
// If we want to, we might do `location.reload();` so that we'd be controlled by it
})
.catch(function(error) {
console.log("Service worker registration failed: " + error.message);
});
}
})();
И в service-worker.js
:
self.addEventListener("message", function(event) {
event.source.postMessage("Responding to " + event.data);
});
Это зависит от event.source
, который поддерживается текущими версиями Chrome и Firefox.
В качестве альтернативы вместо event.source
вы можете отправить сообщение нескольким клиентам сервисного работника, используя self.clients.matchAll
; снова в service-worker.js
:
self.addEventListener("message", function(event) {
self.clients.matchAll().then(all => all.forEach(client => {
client.postMessage("Responding to " + event.data);
}));
});
matchAll
принимает некоторые параметры фильтрации.
Вы сказали, что у вас проблемы с работой. Здесь полная версия того, что работает для меня в Chrome и Firefox:
service-worker.html
:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Service Worker</title>
</head>
<body>
(Look in the console.)
<script>
(function() {
"use strict";
if (!navigator.serviceWorker || !navigator.serviceWorker.register) {
console.log("This browser doesn't support service workers");
return;
}
// Listen to messages from service workers.
navigator.serviceWorker.addEventListener('message', function(event) {
console.log("Got reply from service worker: " + event.data);
});
// Are we being controlled?
if (navigator.serviceWorker.controller) {
// Yes, send our controller a message.
console.log("Sending 'hi' to controller");
navigator.serviceWorker.controller.postMessage("hi");
} else {
// No, register a service worker to control pages like us.
// Note that it won't control this instance of this page, it only takes effect
// for pages in its scope loaded *after* it installed.
navigator.serviceWorker.register("service-worker.js")
.then(function(registration) {
console.log("Service worker registered, scope: " + registration.scope);
console.log("Refresh the page to talk to it.");
// If we want to, we might do `location.reload();` so that we'd be controlled by it
})
.catch(function(error) {
console.log("Service worker registration failed: " + error.message);
});
}
})();
</script>
</body>
</html>
service-worker.js
:
self.addEventListener("message", function(event) {
//event.source.postMessage("Responding to " + event.data);
self.clients.matchAll().then(all => all.forEach(client => {
client.postMessage("Responding to " + event.data);
}));
});
Как вы можете видеть, эта версия использует self.clients.matchAll
, с прокомментированной версией event.source
над ней.
Если я запустил это в двух окнах, каждое обновление каждого окна отправит сообщение другим окнам (потому что я использую self.clients.matchAll
...).