I want to periodically call an API from my service worker to send data stored in the localStorage
. This data will be produced and saved in localStorage
when a user browses my website. Consider it something like saving stats in localStorage
and sending it periodically through the service worker. How should I do this? I understand that I can't access localStorage
from the service worker and will have to use the postMessage
API. Any help would be highly appreciated.
You cannot access localStorage (and also sessionStorage) from a webworker process, they result will be undefined
, this is for security reasons.
You need to use postMessage()
back to the Worker's originating code, and have that code store the data in localStorage.
You should use localStorage.setItem()
and localStorage.getItem()
to save and get data from local storage.
More info:
Pseudo code below, hoping it gets you started:
// include your worker
var myWorker = new Worker('YourWorker.js'),
data,
changeData = function() {
// save data to local storage
localStorage.setItem('data', (new Date).getTime().toString());
// get data from local storage
data = localStorage.getItem('data');
sendToWorker();
},
sendToWorker = function() {
// send data to your worker
myWorker.postMessage({
data: data
});
};
setInterval(changeData, 1000)
var myWorker = new YourWorker('YourWorker.js'),
> new WebWorker
right? –
Transferase new Worker()
:) –
Cryptogram localStorage
in service workers has anything to do with security? The MDN page for service workers mentions only synchronicity, though even that is not backed up. –
Dissatisfy Broadcast Channel API is easier
There are several ways to communicate between the client and the controlling service worker, but localStorage
is not one of them.
IndexedDB
is, but this might be an overkill for a PWA that by all means should remain slim.
Of all means, the Broadcast Channel API results the easiest. It is by far much easier to implement than above-mentioned postMessage()
with the MessageChannel API.
Here is how broadcasting works
Define a new broadcasting channel in both the service worker and the client.
const channel4Broadcast = new BroadcastChannel('channel4');
To send a broadcast message in either the worker or the client:
channel4Broadcast.postMessage({key: value});
To receive a broadcast message in either the worker or the client:
channel4Broadcast.onmessage = (event) => {
value = event.data.key;
}
channel4Broadcast.onmessage
to get initialised first? –
Lilly I've been using this package called localforage
that provides a localStorage-like interface that wraps around IndexedDB. https://github.com/localForage/localForage
You can then import it by placing it in your public directory, so it is served by your webserver, and then calling: self.importScripts('localforage.js');
within your service worker.
https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers says
Note: localStorage works in a similar way to service worker cache, but it is synchronous, so not allowed in service workers.
Note: IndexedDB can be used inside a service worker for data storage if you require it.
Also there is a bit of discussion here: How do I access the local storage using service workers in angular?
Stumbling over this question myself for a tiny webapp-project, I considered the following solution:
When the user is online, the data can be sent immediately. When he is offline, I use the SyncEvent.tag
property to send information from the client to the serviceworker. Like this:
//offline_page.html (loads only, when user is offline)
button.onclick = function() {
//on click: store new value in localStorage and prepare new value for synchronization
localStorage.setItem("actual", numberField.value);
navigator.serviceWorker.ready.then(function(swRegistration) {
return swRegistration.sync.register('newval:'+numberField.value);
});
}
//sw.js
self.addEventListener('sync', function(event) {
//let's say everything in front of ':' is the option, everything afterwards is the value
let option = event.tag.replace(/(.*?)\:.*?$/, "$1");
let value = event.tag.replace(/.*?\:(.*?)$/, "$1");
if(option == "newval") {
event.waitUntil(
fetch("update.php?newval="+value)
.then(function(response) {
console.log(response);
})
);
}
});
update.php
saves the new value to backend, as soon as the user goes online.
This won't give the service worker access to the localStorage, but it will send him every change made.
Just starting to get used to this syncing topic. So I would really be interested, wheather this is helpful and what others think about this solution.
© 2022 - 2024 — McMap. All rights reserved.