Skip to content
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

thoughts on exposing multiple-instances to sites via the DOM #1185

Open
wanderview opened this issue Aug 9, 2017 · 1 comment
Open

thoughts on exposing multiple-instances to sites via the DOM #1185

wanderview opened this issue Aug 9, 2017 · 1 comment

Comments

@wanderview
Copy link
Member

wanderview commented Aug 9, 2017

Issue #756 is about allowing multiple instances of the same service worker to run at the same time. It talks a lot about global state issues, etc. I wanted to make a separate issue for a more focused part of the problem though:

How do we even model multiple instances in the DOM so that sites can understand what is happen?

Right now we have a ServiceWorker object that logically represents a version of the SW script. It also happens to represent the current instances, if it exists, or will auto-spawn that instance if it doesn't exist. So the script version and instance identity are wrapped up in a single object. And we're using object identity between ServiceWorker objects instead of ids, so the identity is pretty strongly defined.

I've been trying to brainstorm ideas on how to add multiple instances to the DOM model here without breaking back compat. Right now it feels like we just have a bunch of bad ideas, unfortunately.

I had an IRC conversation with @jakearchibald about it. I'm pasting it here (with his permission):

10:41 AM <wanderview> btw, I have been thinking more about how to expose
DOM stuff for multi-instances in SW... and I have concluded it sucks and is no good
10:42 AM <wanderview> I'm not sure there is a way to add it in a sensible way
that doesn't break some kind of back compat with current behavior
10:42 AM <wanderview> the ServiceWorker object equality makes this extra hard
10:43 AM <JakeA> As in reg.active == reg.active?
10:43 AM <wanderview> I was more thinking of MessageEvent.source === reg.active
10:44 AM <wanderview> how do we make MessageEvent.source point to the actual
SW that messaged you without breaking those kinds of comparisons
10:44 AM <wanderview> this would be easier if we kept ServiceWorker.id
10:45 AM <JakeA> That assumes that messageEvent.source should point to an exact
instance, and not just represent "an instance of the active worker"
10:45 AM <wanderview> right... I guess I was trying to make postMessage()
from/back-to a service worker "just work" with separate instances
10:46 AM <JakeA> maybe we have to do that… not sure.
10:46 AM <JakeA> If it was opt-in we can break all sorts of rules
10:46 AM <wanderview> I'm sure this will get shot down... but we could add something
like MessageEvent.sourceAsClient and then expose the exact instance as a Client object
10:47 AM <wanderview> (in theory?)
10:50 AM <JakeA> Not a bad idea, but yeah, it comes with that caveat that may be a gotcha
10:51 AM <wanderview> My other idea was to add a ServiceWorker.instanceId... if
instanceId is null then it refers to "any instance of this SW"... that platonic ideal of the
service worker
10:51 AM <wanderview> if instanceId is set then it goes to a specific one
10:52 AM <wanderview> and there is a ServiceWorker.getInstanceList() or
ServiceWorkerRegistration.getInstanceList()
10:52 AM <JakeA> and that would be the case for postmessage?
10:52 AM <JakeA> hmm
10:52 AM <JakeA> I like that less
10:52 AM <wanderview> if the instance goes away it could fall back to the "null" instanceId
behavior
10:53 AM <wanderview> I have many bad ideas
10:53 AM <JakeA> I exclusively have bad ideas
10:53 AM <JakeA> especially with this issue
10:53 AM <JakeA> I guess we shoot for a non-opt-in solution, but I'm not confident
10:53 AM <wanderview> we could also leave everything with ServiceWorker alone... but
then expose Clients API to other globals... and we say if you want to work with multiple
instances use Clients API instead of the ServiceWorker postMessage
10:54 AM <JakeA> thanks for the thoughts on this btw
10:54 AM <wanderview> I like that last one the best, but its the heaviest lift
10:54 AM <wanderview> in terms of implementation, I think
10:54 AM <JakeA> I guess in that case you get messageEvent.clientId?
10:55 AM <wanderview> well, in theory if you get a window.clients.onmessage event its
MessageEvent.source would be the Client that sent it
10:57 AM <JakeA> Hmm, but what if the client goes away and you just want to message
an active service worker in the registration?
10:57 AM <wanderview> well then use the existing ServiceWorker object stuff... that is all
still there
10:57 AM <JakeA> fair, but will you be able to know it was an active service worker that
sent the message?
10:57 AM <wanderview> the Client path would be used if you want multiple-instances
and to coordinate between a window and specific instance
10:58 AM <wanderview> I guess I was thinking the active state would be implicit that
your messaging about things like push events, etc
10:58 AM <wanderview> I mean, the site can include relevent info about the SW in its
message
10:59 AM <wanderview> and I have an issue somewhere to expose Client.type ===
'serviceworker'
11:00 AM <JakeA> yeah, I agree we should too

Edit: Fixed linked issue above.

@wanderview wanderview mentioned this issue Aug 9, 2017
@jakearchibald
Copy link
Contributor

If we added multiple instances today, you could still ensure you were conversing with a specific service worker by either passing a message port with the initial message:

// In the service worker:
const channel = new MessageChannel();
client.postMessage({useThisForReplies: channel.port2}, [channel.port2]);

// In the page:
navigator.serviceWorker.onmessage = event => {
  if (event.data.useThisForReplies) {
    event.data.useThisForReplies.postMessage();
  }
};

Alternatively useThisForReplies could be a random broadcast channel ID.

(this doesn't mean we shouldn't do one of the things @wanderview suggests above, it just hadn't previously occurred to me that there are kinda solutions already)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants