Re: PROPOSAL: New signature for getUserMedia and callbacks

Anant Narayanan wrote:
> What
> --
> Change the signature of getUserMedia to:
>
> navigator.getUserMedia(options, callback);
>
> where option is a dictionary of type UserMediaOptions (currently video and audio are the two allowed keys, but easily extensible to include UserMediaConstraints/Hints), and callback is a single callback invoked in cases of either error or success.
>
> Why
> --
> We've been wanting to steer away from using the two callback approach for a while now.  There are multiple ways to do this. One proposal described using 
events, eliminating callbacks altogether. The usefulness of events in 
the case of getUserMedia was questioned (as it is not a DOM object), and 
the only useful property remaining would be that of multiple listeners.
>
> As we could not reach consensus on that (and events vs. callbacks is more of a style issue that I am willing to compromise on), I propose we use a node.js style callback to achieve the initial goal of moving away from the two callbacks.
>
> The main reason for not wanting to use two callbacks has been discussed before, the WebAPI design community in general has been moving away from this pattern. In summary, we want error handling to be in the default path for developers, and two callbacks always makes the error callback be considered optional.

> By using a single callback, even if the developer doesn't check the value of 'err' in their handler,  an exception would have a reasonable stack trace (this is not true if 
the developer doesn't provide a failure callback and an error occurs).

In this design a developer MUST to check the value of 'err' so it's not 
optional as suggested. More on this below...

Secondly, stack traces occur when exceptions are thrown. Returning an 
'err' object in an async callback, regardless of where that is returned, 
isn't the same as throwing a JavaScript exception. Exceptions are never 
thrown in this design so we aren't dealing with stack traces.

>
> How
> --
> This changes the signature of getUserMedia to:
>
> navigator.getUserMedia(options, function(err, stream) {
> …
> });
>
> i.e. there is only 1 callback, invoked with two arguments err and stream. If an error occurs, err will be set to an appropriate value (which I propose should be string, a separate mail on that will follow) and stream will be undefined. If the call succeeded, err will be undefined and stream will be the MediaStream requested.

What you're proposing is equivalent to:

function handle(obj) {
   if(obj.code) {
     /* process error */
   } else {
     /* process stream */
   }
}
navigator.getUserMedia(options, handle, handle);

Putting the error object on a web developer's critical path is 
unnecessary as it actually forces a developer to add boilerplate 
error/success type checking:

navigator.getUserMedia(options, function(err, stream) {
   // We now MUST check the output before usage since
   // we cannot be sure at this point if we have an
   // error or a stream without the following boilerplate

   if(err) {
     /* process error */
   } else {
     /* process stream */
   }
});

Meanwhile the current proposal removes the need for this boilerplate at 
all if the developer only wants to react when a stream object is 
actually provided:

navigator.getUserMedia(options, function(stream) {
   /* process stream */
} /* just don't process errors. what's the harm? */);

The main question then is why a developer shouldn't just be able to 
ignore a permission denied error if they so wish? Is there any reason 
that a developer MUST handle this error callback in their web applications?

- Rich

Received on Friday, 30 March 2012 14:26:25 UTC