- From: Jonas Sicking <jonas@sicking.cc>
- Date: Wed, 5 Sep 2012 00:49:44 -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 Mon, Sep 3, 2012 at 8:55 PM, Glenn Maynard <glenn@zewt.org> wrote: > On Mon, Sep 3, 2012 at 9:30 PM, Jonas Sicking <jonas@sicking.cc> wrote: >> >> We can't generically block on children since we can't let the main >> window block on a child. That would effectively permit synchronous IO >> from the main thread which is not something that we want to allow. > > > The UI thread would never be allowed to block, of course. The "getMessage" > API itself would never even be exposed in the UI thread, regardless of the > state of this flag. The problem with a "Only allow blocking on children, except that window can't block on its children" is that you can never block on a computation which is implemented in the main thread. I think that cuts out some major use cases since todays browsers have many APIs which are only implemented in the main thread. APIs only existing on the main thread is likely going to always be the case, even once browsers get better at implementing APIs in the main thread and worker threads at the same time, since there will always be some APIs that are main-thread only, like the DOM. >> Your proposal makes it possible for pages to avoid the problems >> described in my email by setting up a separate channel used for >> synchronous messages. But some of the problems still remain. As soon >> as a message channel is used for both synchronous and asynchronous >> messages you can easily get into trouble. If someone calls the >> blocking waitForMessage() function and receive a message which was >> intended to be delivered asynchronously there is no good recourse. >> Basically any time that happens there are only bad options available, >> many of which have subtle problems that only happen intermittently >> like the ones I described in my initial email. >> >> Since that is the case, I think the best solution is to always force >> separate channels to be used for synchronous and asynchronous >> messages. > > If you have messages that must be received synchronously, and other messages > that must be received asynchronously, then that's precisely a time when > you'd want to use MessagePorts to separate them. That's what they're for. > It's the same as using separate MessagePorts when you have two unrelated > libraries receiving their own messages, so each library only sees messages > intended for it. > > I agree that APIs that encourage people to write brittle code should be > squinted at carefully, and we should definitely examine all APIs for that > problem, but really I don't think it's the case here. You are more optimistic than I am. The fact that all the examples that people have used while we have been discussing synchronous messaging have spun event loops in attempts to deal with messages that couldn't be handled by the synchronous poller makes me very much think that so will web developers. And the fact that using the existing communication channel is much simpler than manually setting up a new one using |new MessageChannel| and passing transferring ports using postMessage further adds to that. So I would say that there's a high degree of risk that people will get this wrong. > 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 also wonder if what you are describing doesn't make more sense when communicating with a child worker and blocking on receiving a response from it. Another trait that this looses is the ability to terminate a worker as soon as we know that a synchronous response can't be sent. I.e. in proposal 1 and 2 the implementation can terminate the worker as soon as the object with the .reply() function is GCed. Note that this doesn't expose any GC behavior since a "forever blocked" worker behaves exactly the same as a terminated worker. I.e. neither will ever execute any code. >> All in all this is a much more complicated setup though. I think it'd >> be worth keeping the simpler API like the 1 or 2 proposals even if we >> do introduce SyncMessageChannel since that likely covers the majority >> of use cases. > > > Those proposals seem much more complex to me. You can't send a message that > will be received synchronously unless the other side prompts you for one > first; you have to care whether the other side is acting synchronously or > asynchronously. It's a bunch of new concepts ("synchronous messages", > "message replies"), instead of a simple (to users, at least) addition to > MessagePorts. Fewer APIs isn't the same thing as a simpler API. On the contrary, I think trying to fit too much functionality into the same set of functions can easily result in more complexity. I think this is fairly well illustrated by the set of rules that you ended up having to set up in order to make the "blocking permitted" flags work out correctly. And your algorithm produces weird edge cases, such as that it matters if someone sets up a message "proxy" which forwards all messages from one channel to another, rather than just passes on one end of a channel. With such a "proxy" your ports end up touching more threads and so are more likely to clear the "blocking permitted" flag. In all other cases such a proxy is transparent. The rules I ended up with were much simpler, and all rules could all be checked synchronously meaning that if there's a bug in the code, an exception is immediately thrown, rather than thrown much later once someone tries to use a channel for synchronous messages which had been passed around one time too many. / Jonas
Received on Wednesday, 5 September 2012 07:50:41 UTC