Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
Ben Nadel at BFusion / BFLEX 2010 (Bloomington, Indiana) with: Ed Bartram and Vaughn Bartram
Ben Nadel at BFusion / BFLEX 2010 (Bloomington, Indiana) with: Ed Bartram@edbartram ) and Vaughn Bartram

Always Throw Errors In Order To Get A Stack Trace In Promise Chains

By Ben Nadel on

The other day, I was developing a Promise-based workflow when I ran into a little dilemma. I had a situation in which I needed to raise an exception. But, the path forward, in the heat of the moment, was suddenly unclear; since I was already inside a Promise chain, should I throw the error or reject the error? Luckily, I didn't have to think about this too deeply because IE (Internet Explorer) forced me down the right path. In IE (both 10 and 11), the .stack property of the Error object isn't actually populated until the Error object is thrown. As such, you must throw the Error object in order get a proper stack trace in a Promise Chain (or anywhere else, for that matter).

To see this in action, I put together a tiny demo that rejects a Promise in two different ways: first, with the reject() function and second, with the throw() operation:

  • <!doctype html>
  • <html>
  • <head>
  • <meta charset="utf-8" />
  •  
  • <title>
  • Always Throw Errors In Order To Get A Stack Trace In Promise Chains
  • </title>
  • </head>
  • <body>
  •  
  • <h1>
  • Always Throw Errors In Order To Get A Stack Trace In Promise Chains
  • </h1>
  •  
  • <p>
  • <em>Look at console &mdash; things being logged, yo!</em>
  • </p>
  •  
  • <script type="text/javascript" src="../../vendor/core-js/2.4.1/shim.min.js"></script>
  • <script type="text/javascript">
  •  
  • var promise = new Promise(
  • function( resolve, reject ) {
  •  
  • // If we REJECT instead of THROW ....
  • reject( new Error( "Something went wrong!" ) );
  •  
  • }
  • );
  •  
  • promise.catch(
  • function handleReject( error ) {
  •  
  • console.warn( "Error:" );
  • console.log( error.message );
  •  
  • // CAUTION: In IE 10 / 11, the stack property will be undefined because
  • // the original Error() object was never thrown. IE only populates the
  • // stack at the time the Error is thrown.
  • console.log( error.stack );
  •  
  • }
  • );
  •  
  •  
  • // --------------------------------------------------------------------------- //
  • // --------------------------------------------------------------------------- //
  •  
  •  
  • var promise = new Promise(
  • function( resolve, reject ) {
  •  
  • // If we THROW instead of REJECT ....
  • throw( new Error( "Something went wrong (but better)!" ) );
  •  
  • }
  • );
  •  
  • promise.catch(
  • function handleReject( error ) {
  •  
  • console.warn( "Error:" );
  • console.log( error.message );
  •  
  • // This time, since we threw the error, instead of simply rejecting it,
  • // IE 10 and 11 will populate the stack trace.
  • console.log( error.stack );
  •  
  • }
  • );
  •  
  • </script>
  •  
  • </body>
  • </html>

As you can see, both approaches use the core Promise constructor to initiate the Promise chain. The first fulfills the Promise with the explicit rejection of the Error object. The second throws the Error which will implicitly fulfill the Promise with a rejection of the thrown Error object. In Microsoft Edge and all other modern browsers, the two approaches result in the same output; but, in IE 10 and 11, only the latter provides a stack trace:


 
 
 

 
 IE 10 and 11 only populate the .stack property of an Error object when it's thrown. 
 
 
 

As you can see, only a thrown Error provides a stack trace in IE 10 and 11.

In hindsight, my confusion seems silly. Of course you throw() Error objects - that's the whole point of creating an Error object. But, at the time, with the reject() function right there, I suddenly felt unsure of myself. Thankfully, IE was there to steer me in the right direction (and how many times do you get to say that in your life!?).




Reader Comments

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.