Long-running process inside a Service Worker (or something similar) - javascript

I have a client-side JS app that uses IndexedDB to store its state. Works fine. However, it's kind of slow because I am frequently reading from and writing to IndexedDB so that the state does not become inconsistent when multiple tabs are open.
My idea was... put all DB access stuff inside a Service Worker, and then I can cache values there in memory without worrying that another tab might have altered the database.
That seems to work fine, except some parts of my application take a long time to run. I can communicate the status (like "X% done") from the Service Worker to my UI. But both Firefox and Chrome seem to kill the worker if it runs for more than 30 seconds, which is way too short for me.
Is there any way around this limitation? If not, any ideas for achieving something similar? A Shared Worker could do it I think, except browser support is poor and I don't anticipate that improving now with the momentum behind Service Workers.

The Google documentation on service workers tells us that using service workers as a memory cache is impossible:
It's terminated when not in use, and restarted when it's next needed, so you cannot rely on global state within a service worker's onfetch and onmessage handlers. If there is information that you need to persist and reuse across restarts, service workers do have access to the IndexedDB API.
My suggestion is to keep using service workers to persist data to the database, and use localStorage to create a shared cache between pages. The tab that is making the change is then responsible for both updating the cache in localStorage and persisting to IndexedDB through the service worker.

I ended up using a Shared Worker. In browsers that don't support Shared Workers, such as Edge and Safari, I fall back to a Web Worker and some hacky code to only let you open the app in one tab at a time.
Since 90% of my users are on Firefox or Chrome anyway, I figure it's not a huge loss.
I also wrote a library to (amongst other things) normalize the APIs used in Shared Workers and Web Workers, so I have the exact same code running in both scenarios, the only difference is whether the worker is initialized with Worker or SharedWorker.

As you said yourself SharedWorkers seems to be exactly what you need.
I'm not sure why you think the momentum behind implementing ServiceWorkers prevent browsers from supporting SharedWorkers. They seem to be two different kind of beasts.
As far as I understand ServiceWorkers should be used as a proxy for your requests when your application is offline and heavy stuff should be done in WebWorkers and SharedWorkers
https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API
https://developer.mozilla.org/en-US/docs/Web/API/SharedWorker

Related

Can web workers be restarted by the brower at any time?

I've read in many places (including here, in Stack Overflow) that web workers can be killed and restarted by the browser at any time. Well, probably "at any time" means "as long as they are doing something", but the thing is that they can be killed and restarted by the browser without prior warning, losing any data stored in globalThis.
But for the life of me I cannot find that in the specification, and it worries me because I'm actually using a Web Worker whose proper functioning relies in keeping some info data in a global variable to keep minimal state between calls of the message handling function.
This web worker works like a charm, and state is kept unless of course the page is refreshed, but I'm afraid that the app can fail if the browser decides to restart the web worker, and for sure it will if that happens.
I've googled about this, specially looking for examples and alternatives for rewriting my web worker without the need for that global state, but I haven't found anything relevant.
Can anyone point me to some official information about this?
I've read in many places (including here, in Stack Overflow) that web workers can be killed and restarted by the browser at any time.
Nope, they won't ever restart your (dedicated) Worker in any way.
The browser can kill a Worker if
The main navigable (a.k.a "page") is killed.
The Worker#terminate() method has been called.
The DedicatedWorkerGlobalScope#close() method has been called, and the current task is completed.
The Worker becomes "orphan". This may happen when it stops being a "protected worker", i.e.
when the Worker is a sub-Worker (itself created from a Worker) and its owner has been killed,
or when it has no scheduled tasks, no ongoing network request or database transaction, and no MessagePort or inner Worker objects susceptible of receiving messages from the outside.
So as long as you keep a reference to your Worker object in your main thread, and don't call yourself one of the closing methods, there is no way the Worker can be killed by the browser.
Note: The rules for SharedWorkers, ServiceWorkers, and other Worklets are all different, this answer treats only Dedicated Workers, created from new Worker().

Web - what is the differences between periodic sync and sync?

I came across two different types of sync in the background for PWAs sync and periodic sync. there are not many resources for them and existing resources do not explain enough with sample working codes.
so my main question is: are there any other logical differences between them other than frequency?
and my side question is: are they handling requests by themselves? I'm asking this because I want something more flexible, I mean I'm managing offline and online situations and saving data in IDB them I'm offline and I just need a background process to get my offline data from my custom IDB and send them to the server.
Here's a few use cases that can help illustrate the difference. Also keep in mind that as of Feb. 2021, the Background Sync is only available in Chrome and Chromium-based browsers, and Periodic Background Sync is only available in Chrome after a progressive web app has been installed.
Background Sync
The use case is retrying a failed update/upload operation (usually a POST or a PUT) "in the background" at a regular interval, until it succeeds. You could imagine, for instance, trying to upload a new photo to a social media site, but your network connection is down. As a user, you'd want that upload retried at some point in the future.
The API only provides the mechanism for triggering an opportunity to re-attempt the network operation, via a sync event in the web app's service worker. It's up to a developer to store information about the failed request (usually in IndexedDB) and actually resend it, and indicate whether the sync was successful or if it failed again.
(The workbox-background-sync library can help with the implementation details, if you'd rather not deal with everything yourself.)
Periodic Background Sync
The use case is refreshing caches "in the background" so that the next time a user opens your web app, the data is fresher than it otherwise would be. You could imagine an installed news progressive web app using periodic background sync to update its cache of top headlines each morning.
Under the hood, this works by invoking a periodicsync event in your service worker, and inside that event handler, you'd normally make a GET request to update something stored in the Cache Storage API or IndexedDB.

Clear a PWA's cache periodically using javascript

I need all of the users of my application(desktop and tablet users) to start everyday with an empty cache.
Is there any way I can take advantage of service workers to achieve this?
Has anybody ever tried to do this? Or do you think there's a better way to run a schedule tasked on all the devices where my PWA is installed.
Thanks
Service worker cache super-cedes browser cache and honestly you should focus more on it than browser cache.
There is not a way to purge browser cache via the service worker or UI script for that matter. You have no control over that.
Even setting the Cache-Control header may not really matter. Browsers can be more aggressive as they deem necessary. Routers, load balancers, etc call get in the way as well.
If you are using service worker cache you can invalidate it any way you want. I have made some very sophisticated service workers, especially in recent months around invalidating cached assets in SW cache and indexedDB.
It is way more complex than I can share here LOL. There are numerous strategies you can employ, it all depends on what goals you have and what call the persona of your network addressable assets :)

Service workers and page performance

I'm stuck at a wedding reception that I really don't want to be at and I'm driving, so obviously I'm reading about service workers. I'm on my phone so can't play about with anything but was thinking if they're a viable option for improving page performance?
Images are the biggest killer on my site and I'm half thinking we could use a service worker to cache them to help get page load times down. From what I can tell, the browser still makes the http request, it's just the response is from the SW cache, not the file location. Am I missing something here? Is there therefore any actual benefit to doing this?
While the regular http cache has a lot of overlap with ServiceWorker cache, one thing that the former can't handle very well is the dynamically generated html used in many client-side javascript applications.
Even when all the resources of the app are cache hits, there is still the delay as the javascript is compiled and executed before the app is usable.
Addy Osmani has demonstrated how ServiceWorker can be used to cache the Shell of an app. When the DOM is modified on the client, it is updated in the cache. The next time that URL is requested, the ServiceWorker replies with html that is ready for use before the app has booted.
The other advantage regards lie-fi: when it seems the network is available, but not enough packets are getting through. ServiceWorkers can afford to have a near-imperceptible timeout, because they can serve immediately from cache and wait for the response to load (if ever).
Your consideration is invalid.
Service worker is designed to work like a proxy server that can especially handle some off-page operations like offline ability, push notification, background synchronization, etc. So in your case, you will gain no performance benefits by caching images with service worker over the traditional browser's cache approach.

What local storage in html5 can I use safely in the browser ui thread and the web worker thread

I've been trying to use web sql database api in webkit based browsers. I have been using the async api in the main ui thread and a web worker. Both threads access the same database (which as you know is sqlite underthehood)
Everything behaves fine but occassionally transactions are lost or one transaction fails and it seems to be a timing/race condition. It appears access to the underlying sqlite database is not thread-safe.
A bit more background. My web worker is simply executing a query against a table that may have a record inserted into it from the main ui thread.
I am wondering if it is actually documented somewhere what local/web storage can be accessed safely from both the ui thread and the web worker thread? I've read somewhere that the indexeddb api is thread safe but that does not help me right now since browser support for it is poor/non-existent for the browsers I am targeting (at least I think so - I get my information from http://caniuse.com )
Any insights would be gratefully received
You can't use localStorage or sessionStorage from WebWorkers.
While both are synchronous operations they aren't a real issue for simple data writing and reading. The issue is more relevant at browser start-up, but that's a browser implementation issue.
Take a look at this, it should help: http://www.nczonline.net/blog/2012/04/25/the-performance-of-localstorage-revisited/

Categories

Resources