Use ".then(null, Cu.reportError);" with Promise.jsm

Joe Walker jwalker at mozilla.com
Sat Aug 10 11:33:12 UTC 2013


Promise chains often look like your examples, but with an extra feature:

    something.then(result => {
       *return*  step1.then(result => {
         *return*  step2.then(result => {
           *return*  42;
         });
       });
    }).then(console.log, console.error);


I added ".then(console.log, console.error);" to make it show what 
happens and some "returns" to make it more obvious what was going on.

The result of the above code would be console.log(42); because
* the result of a call to "then" is a promise of the return value of the 
function
* and promises internally resolve a promise of a promise of a thing, to 
be a promise of a thing

Clearly this can be (and often is) split up into several parts:

    something.then(result => {
       *return*  step1.then(doStuff);
    }).then(console.log, console.error);

    function doStuff(result) {
       *return*  step2.then(doMoreStuff);
    }

    function doMoreStuff(result) {
       *return*  42;
    }


Looking at doStuff and doMoreStuff saying "Where is the error 
handling?", misses that the error handling is in the thing that called 
doStuff.

The lack of a 'return' statement doesn't change this, because without an 
explicit return, the "then" function just returns a promise of 
undefined, which works like "Tell me when you're done".

The ratio of promise uses to error handling is surprisingly lopsided. I 
believe the GCLI code does error handling properly and the ratio there 
is 23 places where errors are handled, and 124 places where 'then' is 
called, and not 1:1. I just did a very quick scan through the devtools 
code, and I could believe that the ratio was similar there too.

Joe.

On 10/08/2013 04:04, Mark Hammond wrote:
> On 9/08/2013 8:32 PM, David Rajchenbach-Teller wrote:
>> Furthermore, I *strongly* suggest that we r- any promise chain that does
>> not report errors, unless there is a comment explaining why we do not.
>
> This concept of a "promise chain" escapes me.  I understand that 
> conceptually, promise code should look like:
>
>   something.then(step1)
>            .then(step2)
>            .then(step3)
>            .then(null, Cu.reportError)
>
> One nice promise chain and the final .then() looks reasonable. But 
> every time I try and use promises, they actually end up looking like:
>
>   something.then(result => {
>     step1.then(result => {
>       step2.then(result => {
>         step3.then(result => {
>         });
>       });
>     });
>   })
>
> in that case we have 4 "promise chains".  Thus, we need 4 extra 
> .then(null, Cu.reportError) calls, making the code much larger and 
> harder to follow.
>
> At first I thought it was just me, so I started digging around in our 
> code.  I looked at non-test code in browser/base and toolkit/ (but 
> stopped at devtools), and examined over 30 calls to .then() - and 
> couldn't find a *single* case of a promise chain.  The closest I could 
> find was a few places where .then(null, Cu.reportError) was correctly 
> at the end, giving a promise chain of length 2.
>
> So, in practice in our code, *every single* .then() call must have 
> .then(null, Cu.reportError) tacked onto the end.  Given so few of our 
> existing ones do this, fixing this code would require nearly doubling 
> the number of .then() calls in the code.
>
> While most don't have any error reporting, the ones that do attempt to 
> handle errors may or may not be correct, depending on your subjective 
> viewpoint.  For example, code like:
>
>    .then(null, error => {
>       this.foo.bar = "error";
>     });
>
> is still poor form IMO - in exceptional circumstances, this.foo might 
> be null, so a final .then() should still be used even if the error 
> looks extremely unlikely.  This is a subjective call, and they are 
> hard to get right - is the final .then() really necessary there? Would 
> the "unless there is a comment" clause get us out of this?
>
> So - I couldn't find a single "promise chain", and the vast majority 
> of promises fail to handle errors correctly.  Of the ones that *do* 
> handle errors correctly, overwhelmingly they do the trivial 
> .then(null, Cu.reportError).  I could only find a few cases that used 
> more sophisticated error handling.  Or to put it another way - if 
> promises magically reported errors, there would only be a few 
> onRejected handlers left in the code I examined and the vast majority 
> of our code would suddenly become correct without any further changes.
>
> IMO, something is very wrong with this picture.  Please understand I'm 
> not looking to blame anyone or anything.  Promise-based code, at first 
> glance, looks like a huge improvement over what we were doing before. 
> It just concerns me that to do it right means bloating the code with 
> onRejected handlers that just do what should be done automatically 
> anyway - and that clearly we've failed to do this in the past, so I'm 
> not confident we will consistently do it correctly in the future.
>
> I'm relatively new to promises so apologize if I got any of the 
> details above wrong.  Also, I didn't do a thorough examination of all 
> promises in the tree, so I may have overlooked significant chunks of 
> code that don't suffer the problems I've mentioned above (but if I 
> have, please point it out to me so I can learn from it!)  This 
> conversation is purely motivated by the fact that I like compact code 
> so my brain doesn't overflow, and that I personally screw things up so 
> often that without good, reliable error reporting I fail to achieve 
> anything at all :)
>
> Cheers,
>
> Mark
>
> _______________________________________________
> firefox-dev mailing list
> firefox-dev at mozilla.org
> https://mail.mozilla.org/listinfo/firefox-dev

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/firefox-dev/attachments/20130810/c30fcaa9/attachment.html>


More information about the firefox-dev mailing list