-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Single instance on multiple tabs #1
Comments
Sorry for the late response, I've actually been thinking about this for a while, and you're correct I'll get right on it |
Thanks for your reply! Can I help somehow? |
Sure, I'm about to have a coding sesh, you can join if you'd like |
My issue is similar to this. Right now, I'm thinking of creating a "SharedWorker" within ServiceWorkers by only allowing required actions (in my case, network requests to the backend server) to be performed by the ServiceWorker associated with the first opened tab for an origin. The other tabs will register the requests in an IDB store I'd be curious to see what you guys can come up with for this - perhaps BroadcastChannel would be a simpler mechanism! Though, I suspect my method will be necessary for my needs, since I'm not so much trying to sync tabs as consolidate unique network requests into a single batch request. Edit: Now that I think of it some more, I'm not even sure a SharedWorker could even do what I'm looking for. I just figured through some async/await mechanism the ServiceWorkers would just wait for the SharedWorker to process the various requests. But it really might just be necessary (or at least prudent/robust) to have that IDB queue in the middle... Edit 2: Or maybe it actually is all quite similar - LiveQuery uses BroadcastChannel for part of its magic. Hopefully my ramblings here provide some spark! |
@nickchomey Why not just use cache storage to store responses and check if a response has already been cached, it's what I used for bundlejs.com |
Thanks for the suggestion! I already am planning to use cache storage or, more likely, IndexedDB to store responses. This particular mechanism is for a periodic call to the server to check for any updates (its a highly dynamic site with social networking etc...) and each tab will be looking for different updates. So, rather than have each tab sending a request every minute (on its own schedule, depending on which second of the minute each was opened), I'd like to consolidate all requests into a single request that is sent to the server at, say, 0 seconds of each actual minute of the clock. Benefits of this are:
Perhaps someday I'll implement some WebSocket mechanism that'll obviate the need for all of this, but it won't happen for now. And, moreover, perhaps someday I'll implement a sort of Headless WP that purely uses REST API or GraphQL, but again not for now. So, this seems like a reasonable approach. In fact, it seems pretty much equivalent to this JSON Batching mechanism that Microsoft has. I also use a similar mechanism with Elasticsearch's mget (batch query) API - one request from the webserver performs many search queries across a variety of indices, which php then parses and combines as-needed before being sent to the browser. Sorry for surely cluttering the discussion here, but I hope that it provides a spark of inspiration in some way! |
I would be hesitant to use IndexedDB, it's less reliable than Cache Storage, plus Cache Storage is meant for storing large pieces of data, so you may want to look into it |
Thanks. I will experiment with both, but I strongly suspect idb is the way to go for my application. It supports more granular querying and Dexie makes it easy, flexible and robust to use. Idb also has larger storage limits and I believe longer persistence is possible as well. |
I'll let you folks know if I can figure out this SharedServiceWorker via dexie thing. It might be a decent solution for chrome for android and other incompatible browsers. |
Looks like the RxDB package already implements pretty much exactly what I had tried to describe - they call it Leader Election, which itself is an already-defined software pattern. They talk about it in their discussion of Multi-tab support as a potential solution to the lack of SharedWorker support in browsers. The free version of RxDB works on top of Dexie, so looks like I'll be using that.. Hope this helps! |
Awesome, I'll look into that |
I just noticed this issue, I had started developing a ponyfill for this purpose (inspired by & links to this repo) using leader election and broadcast channels for browsers that don't support shared workers. I did get it working but it could've been better; I'm re-writing it now and it should end up as more of a polyfill than a ponyfill so from a worker script's perspective, it'll be no different than a real shared worker with some caveats of course, such as if the leader tab gets closed, the worker will then get re-started in a different tab and that my implementation seemingly doesn't care whether the worker script is classic or module, either will work thus setting the type in worker options isn't really needed. It is indeed much more complex and I ran into a fair bit of edge cases when first implementing it, haven't ran into all of those in the new re-implementation yet though. One being that in one browser (chrome? iirc?) if the window was minimized/not completely visible, that it would lower worker priority thus making timers execute much slower and initially leader election was based on a ping timeout algorithm to know if a worker was closed/stopped responding; with the re-implementation, I haven't seen that issue just yet though I'm considering alternatives if I can get them working reliably. My personal use case was wanting to have a single shared websocket connection across all tabs; serviceworkers won't let you do this, sharedworkers are great for it but aren't supported in some cases and simply polyfilling with a dedicatedworker defeats the goal of having a single websocket connection (thus defeats the main purpose of even having websockets in a worker) Not sure if there's any interest here in my implementation but I thought I would at least mention it for discussion purposes. |
Oh, wow, yeah I'm interested. I was working on that very thing a couple months ago but I ran out of time and haven't been able to go back and try to implement this 😅 |
Yeah, definitely.. I've been working on it for the last few days and as I said, it can be a tiny bit complex; I did post my previous version to GitHub but I'm not sure if it was complete or fully functional, I know I was at least close to considering it finished enough to be usable but I don't think I got all the way there - https://github.com/Shaped/SharedDedicatedWorkerPonyfill -- as you can see in the My previous version had a few issues though and wasn't really a polyfill, more of a ponyfill I guess - actually, I had never heard of the term ponyfill until I saw it in your project with the conveniently included definition - and a few things were a bit odd about it. One example being that it required the worker script to be implemented as a class that extended a sort of wrapper class. The worker parent class would just define some private values as well as having accessors for Another example was that scripts were loaded weirdly; I can't recall the exact details but from memory but I think I had an issue in some scenarios using For workers as modules, it would load them using a dynamic import (ie. an For workers that weren't modules, the worker shim would use And - just writing that out was painful. It's terrible but it seemed to be what I had to do at the time to get things working regarding loading/importing scripts. Plus, requiring the end-user/developer to have their worker script be implemented as a class extending another class yet not providing any additional functionality above the polywantsaponyfilling/sharedworkeremulation was a bit silly as well. To be fair, I write mostly everything in classes and didn't initially expect to share the code so it wasn't really an issue for myself, but for general developers, yeah it's silly. So I decided to start re-writing it from scratch. I haven't yet run into any issues with loading/importing scripts like before that resulted in the weird The plan now is to not require the end-user/developer to do anything special; any existing shared worker script should work fine. You can, optionally, have your worker export a default class which the shim will instantiate passing the port to the constructor, but this is an optional extra. That will also allow it to be implemented as an actual polyfill, defining There are some options and configuration. You can set the interval between worker pings, the length of time for if a worker doesn't respond or ping to consider it timed out resulting in new leader election, the length of time to wait for a worker to respond when initially loading, whether to force usage of Then, basically it loads, determines whether to use If it's shared, it will do a The worker shim handles proxying things like As real From the perspective of the script loading the worker, the result of So far the biggest difference I've run into in my new implementation is that for the native As of now, it's mostly working as expected with both Shared and Dedicated worker types with leader election/timeouts/loading new workers when using dedicated if the leader tab closes. I need to finish all the wrapping/proxying to ensure messages go to the appropriate port/broadcast channel as needed, do my best to ensure that the worker doesn't see anything out of the ordinary (eg. avoiding polluting I would be interested in any insights or feedback you might have being someone aware and knowledgeable about this. I'm hoping to get my new version in a state that is suitable for posting shortly, I'm happy to share it here once I do if you're interested and it will still be under MIT if you wanted to use it or steal from it ;-) ..and wow that message was way longer than I intended..lol |
So I was just poking around MDN, seems That explains why I had issues before and not now.. Now the question is whether I want to implement my previous work around for older Firefoxen.. Although FF isn't really a target needing fill anyway, though I thought for some reason SharedWorkers weren't available in private tabs but maybe that was just serviceworkers..? hmmmm! |
Since Chrome on Android still does not seem to support SharedWorkers, is there an established solution? |
I was working on this, but I don't really have time to complete it |
Is your feature request related to a problem? Please describe.
From the source, it seems that this library wraps a normal Worker in case there is no SharedWorker.
However, a SharedWorker is only instantiated once per origin/url. Does this library handle this as well?
Describe the solution you'd like
One tab could host the actual worker and the other tabs could be tricked into delegating everything to a
BroadcastChannel
, which the Worker also listens on.Describe alternatives you've considered
None
The text was updated successfully, but these errors were encountered: