- From: Jan-Ivar Bruaroey <jib@mozilla.com>
- Date: Thu, 02 Oct 2014 10:09:51 -0400
- To: Harald Alvestrand <harald@alvestrand.no>, public-media-capture@w3.org
- Message-ID: <542D5CAF.4030402@mozilla.com>
On 10/2/14, 5:00 AM, Harald Alvestrand wrote:
> On 10/01/2014 10:05 PM, Jan-Ivar Bruaroey wrote:
>> First, here's a fiddle [2] showing how promises handle errors correctly:
>>
>>
>> <div id="log"></div>
>>
>> var div = document.getElementById("log");
>> var log = msg => (div.innerHTML = div.innerHTML + msg + "<br>");
>>
>> new Promise(resolve => resolve())
>> .then(() => log("success1"), () => log("fail1"))
>> .then(() => {
>> log("success2a");
>> barf;
>> log("success2b");
>> }, () => log("fail2"))
>> .then(() => log("success3"), () => log("fail3"))
>> .then(() => log("success4"), () => log("fail4"))
>> .then(() => log("success5"), () => log("fail5"))
>> .catch(() => log("failure"));
>>
>
> Now this is interesting, not because of its relationship to
> getUserMedia, but because of what it says about the additional
> functionality of promises....
>
> In the callback world, we insist that gUM calls *one* function, *once*.
> In the promises world, we say that a promise can call *any number* of
> functions - and which ones get called is not going to be obvious.
That's a mischaracterization, so I fear my example is confusing. Whether
you use promises or callbacks, gUM only calls *one* success function,
but that consumer function typically launches everything that follows,
including potentially more asynchronous steps like
peerConnection.createOffer and so on. That's a chain whether you use
promises or callbacks, no difference.
What's different is that with the callback pattern, it's near impossible
to NOT react with anything but total failure of all subsequent steps (I
think we presume this to be OK in gUM/WebRTC as it tends to be OK in
simple demos). In other words, there's no room for handling errors along
the way like you can in synchronous code using try/catch.
Maybe this helps:
My example is uncommon, because people typically DON'T put in rejection
handlers for every promise step, because that's analogous to using
try/catch on EVERY statement (promise.catch(f) is after all an alias for
promise.then(null, f):
// Synchronous code analogy to my very non-gUM example above
try { step1(); } catch (e) { log ("fail1"); }
try { log("success1"); step2(); } catch (e) { log ("fail2"); }
try {
log("success2a");
barf;
log("success2b");
} catch (e) { log("fail3"); }
try { log("success3"); step4(); } catch (e) { log ("fail4"); }
try { log("success4"); step5(); } catch (e) { log ("fail4"); }
try { log("success5"); } catch (e) { log ("failure"); }
Which you would never do in most gUM/WebRTC demos! A more common thing
is to omit rejection-handlers, letting errors "bubble up", just like
people don't normally try/catch every statement). Here's that fiddle [1]:
<div id="log"></div>
var div = document.getElementById("log");
var log = msg => (div.innerHTML = div.innerHTML + msg + "<br>");
new Promise(resolve => resolve())
.then(() => log("success1"))
.then(() => {
log("success2a");
barf;
log("success2b");
})
.then(() => log("success3"))
.then(() => log("success4"))
.then(() => log("success5"))
.catch(() => log("failure"));
This produces what you probably expected:
success1
success2a
failure
And matches the pattern useful for simple gUM/webRTC demos.
> On the other hand, success4 got called exactly as expected, despite
> the fact that something went boom somewhere in the processing. So if
> you want to be sure 2 success handlers get called on success, you have
> to do:
>
> <promise-generator>
> .then(success1, failure1)
> .then(null, failure-in-handler-set-1)
> .then(success2, failure2)
> .catch(failure-in-handler-set-2)
>
> That's not necessarily a bad thing. But it's not unsubtle either.
Again I think you're taking the wrong lesson from my perhaps overly
complicated example. In practice I think you'll see little reason to
distinguish between the synchronous setup of an async function - like
say peerConnection.createOffer - and the asynchronous part that follows,
because if the setup fails then likely the async call wont go well
either, but you're welcome to split things into as many parts as you
wish. Again, for gUM and WebRTC, where each step tends to rely on the
success of the previous step, the fiddle below is more appropriate. It
just doesn't highlight all possibilities with error handling.
.: Jan-Ivar :.
[1] Firefox: http://jsfiddle.net/jib1/0h2jon2L - Others:
http://jsfiddle.net/jib1/9dvbxmoh
Received on Thursday, 2 October 2014 14:10:24 UTC