Re: Web workers: synchronously handling events

On Wed, Dec 29, 2010 at 10:33 AM, Glenn Maynard <glenn@zewt.org> wrote:
> On Wed, Dec 29, 2010 at 4:56 AM, Jonas Sicking <jonas@sicking.cc> wrote:
>> I definitely agree that workers need more features to take advantage
>> of the fact that they are running on their own event loop. One of
>> which is the one you are asking for.
>>
>> We could add something like:
>>
>> boolean checkPendingMessages();
>>
>> which would return true if there are pending messages. The script
>> running in the worker could use this information to return to the
>> event loop to process these messages only when needed. One downside
>> with this API is that there is a risk that people could write:
>
> Is there a problem with synchronously delivering the next pending
> message event, rather than having to return all the way out to allow
> it to run?  Code shouldn't need to be engineered to allow returning
> and resuming in order to receive messages, as if we're still in a UI
> thread.
>
> Note that it's critical that this run only events from a specific
> message port, so only targetted messages are run and not unrelated
> ones.
>
> I've used this approach with C++ worker threads and it works very
> well; it allows thread work to be cancelled at specific, predetermined
> points, without exposing significant threadsafety issues to the thread
> itself, and allowing deeply nested algorithm code to handle
> cancellation in a consistent way:
>
> var checkForCancellation()
> {
>    // run all waiting messages from this port
>    while(cancellationPort.runPendingMessage())
>        ;
>    // if a message set cancellation, stop working
>    if(cancel)
>        throw "Operation cancelled";
> }
>
> try {
>    checkForCancellation();
>    doStuff();
>    while(var i = 0; i < longRunningLoop; ++i)
>    {
>        checkForCancellation();
>        doMoreWork();
>    }
> } catch...
>
>> An alternative solution would be something like:
>>
>> MessageInfo getMessageIfExists();
>>
>> which would return an object containing the message data if a message
>> was pending and remove the message from the queue of pending messages.
>> If there are no pending messages null is returned and the message
>> queue remains empty. This makes it significantly harder to write code
>> like the above. However it might make coding somewhat more awkward
>> since you likely will have to deal with messages arriving two ways,
>> through the normal event loop and through getMessageIfExists.
>
> I avoided that in my suggestion, since it seems likely to cause
> confusing bugs and it's hard to think of when this behavior would
> really be wanted.  If it was, you could do something like this, I
> think:
>
> function getPendingMessageWithoutDelivery(port)
> {
>    var onmessage = port.onmessage;
>    try {
>        port.onmessage = null;
>        return port.runPendingMessage(); // returns the handled
> message or null if none
>    } finally {
>        port.onmessage = onmessage;
>    }
> }

Yeah, this might be a better design. I don't feel strongly between
your port.runPendingMessage() or my getMessageIfExists() proposals.
They both allows for the same use cases to be solved. Your example
code above shows that port.runPendingMessage can be used to implement
getMessageIfExists, it can equally be shown that getMessageIfExists
can be used to implement port.runPendingMessage().

/ Jonas

Received on Thursday, 30 December 2010 06:50:01 UTC