I want to create a timer, which starts the countdown on notification click.
My sample works well as long as the break length is less than one minute. When the break length is longer than a minute, service worker stops working.
index.html
<!DOCTYPE html>
<html>
<body>
<button onclick="notify();">notify</button>
</body>
<script>
function notify() {
const items = ["First", "End of the break", "Second"];
const options = { data: items };
if ('serviceWorker' in navigator) {
Notification.requestPermission()
.then(() => navigator.serviceWorker.register('sw.js'))
.then(() => navigator.serviceWorker.ready
.then((s) => {
s.showNotification('Click to begin', options);
}))
.catch(e => console.log(e.message));
}
}
</script>
</html>
sw.js
let data = [];
let num = 0;
self.onnotificationclick = (event) => {
event.notification.close();
if (event.notification.data) {
({ data } = event.notification);
}
if (num < data.length) {
setTimeout(() => {
self.registration.showNotification(data[num]);
num += 1;
}, num % 2 === 0 ? 1 : 3000);
}
};
I am aware that there should be no setTimeout
in sw.js
, but it's the closest to the point I want to achieve.
Is there a way to build a timer that starts counting down when you click a notification and notifies you about the end of countdown?
(This is a long answer as there are a few things to discuss with your question)
The way service workers are designed is that you should do your work as quickly as possible and return control over to the browser. This is done by via the event.waitUntil(<promise>)
function where you tell the browser you are busy by not resolving the promise you pass in.
In your above example, you aren't using event.waitUntil()
which could prolong the live of a service worker.
For example, you could try:
self.onnotificationclick = (event) => {
event.notification.close();
if (event.notification.data) {
({ data } = event.notification);
}
if (num < data.length) {
event.waitUntil(new Promise(function(resolve, reject) {
setTimeout(() => {
self.registration.showNotification(data.num);
resolve();
}, 3000);
})
}
};
However if you set a timeout that is deemed too long (and it's up to the browser to decide what is too long), the browser can terminate the service worker, resulting in an unpredictable experience for your users.
This is because your intended use case is generally not what the service worker API is designed for. There were proposals for alternative API's, but not of them gained traction (or at least not that I'm aware of - although that was a while a go).
Another note: The use of global variables in a service worker should be used with caution. Like I said, a service worker can be started and terminated frequently, so reading / writing from indexDB may be more appropriate for storing information.
With respect to longer duration timers, there is currently (April 2021) work being done on the Notification Trigger API.
Comments for the Google developers can be left as an issue in the dedicated GitHub repository.
Feedback from the Chrome M80-M83 Origin Trial is also available.
Currently, there is a need to set the #enable-experimental-web-platform-features
flag in chrome://flags
for it to work. As soon as this API becomes stable and mainstream, I will update this answer with code.
Finally, there are more examples and tests in this excellent overview about task scheduling in the service worker. This also deals with the Periodic Background Sync API.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With