- From: Jonas Sicking <jonas@sicking.cc>
- Date: Wed, 5 Sep 2012 19:03:31 -0700
- To: Glenn Maynard <glenn@zewt.org>
- Cc: Andrea Marchesini <amarchesini@mozilla.com>, David Bruant <bruant.d@gmail.com>, "public-webapps@w3.org" <public-webapps@w3.org>
On Wed, Sep 5, 2012 at 12:49 AM, Jonas Sicking <jonas@sicking.cc> wrote: >> Importantly, the sending side >> doesn't have to know whether the receiving side is using a sync API to >> receive it or not--in other words, that information doesn't have to be part >> of the user's messaging protocol. > > I agree that this is desirable trait. But so far I think the risks in > encouraging event loop spinning outweigh the benefits. I did some more thinking about this and came to the following conclusions: The part that I dislike about having single channel used for both sync and async messaging is that you end up with one or more async listeners which expect to get notified about all incoming messages, but then you have an API which "steals" a message away from those listeners. On top of that it has to do that stealing without any way of ensuring ensuring that it actually steals the right message. It has to simply rely on prior information and hope that no unexpected messages sneak in where not expected. Basically any time you use the sync API to pull out a message and get one that wasn't exactly the one you wanted, you have lost. I think all solutions for dealing with that situation are too brittle and all have side effects which will behave very intermittently and result in hard-to-find bugs. However, I do like the idea of the async side of a channel not caring about if the other side is synchronous or not. Though no matter what we do, the async side can't be completely agnostic to if the other side uses blocking reads or not since if the other side wants to use blocking reads, the async side is limited in where it can pass its port. But being (mostly) agnostic to if the other side is using sync messages or not doesn't mean that the other side uses both sync and async messaging! So what we could do is to create a SyncMessageChannel where the async port looks exactly like the port of a normal MessageChannel. That way a worker (or main thread) which provides an asynchronous API by receiving a port to communicate to, can with no effort both accept the port of a MessageChannel as well as the async side of a SyncMessageChannel. Hence I think something like the following would work: [Constructor] interface MessageChannel { readonly attribute MessagePortSyncSide syncPort; readonly attribute MessagePortAsyncSide asyncPort; }; interface MessagePortSyncSide { void postMessage(any message, optional sequence<Transferable> transfer); any waitForMessage(); void close(); }; MessagePortSyncSide implements Transferable; interface MessagePortAsyncSide : EventTarget { void postMessage(any message, optional sequence<Transferable> transfer); void start(); void close(); // event handlers attribute EventHandler onmessage; }; MessagePortAsyncSide implements Transferable; Where there's the additional limitation that MessagePortSyncSide can only be transferred though MessagePortAsyncSide.postMessage() or Worker.postMessage(), and MessagePortAsyncSide can only be transferred though MessagePortSyncSide.postMessage() or DedicatedWorkerGlobalScope.postMessage(). Note that even MessagePortAsyncSide is fully API compatible with the normal MessagePort, but code can still differentiate between the two by using the instanceof operator or Object.toString(). I'm still not convinced that this is a better API than the ones proposed in Olli's proposal 1 and proposal 2, but I think it's an option. What I like about proposals 1 and 2 is that they optimize for the common case of simply wanting to perform a function call in a different thread and waiting for an answer. We could even add a .throw() function in addition to .reply() which makes the caller throw an exception, very similar to ES6's generator.throw(). / Jonas
Received on Thursday, 6 September 2012 02:04:29 UTC