1

My application has many modules and uses promises all over the place.

On occasion, deep in one of these modules, my code throws an exception and the promise chain gets rejected. If this error was reproducible, I could single step until I found the exception. But it's not.

How do I get nodejs to generate a traceback to identify the guilty module, function and line of code?

Here is a trivial example.

'use strict';

// pretend multiple modules, each with deep complicated chains of Promises 
Promise.resolve()
   .then(() => { return Promise.resolve() })
   .then(() => { return Promise.resolve() })
   .then(() => { return Promise.resolve() })
   .then(() => {
       x = "find me if you can, x is very common variable name";
       return Promise.resolve
   })
   .then(() => { return Promise.resolve() })
   .then(() => { return Promise.resolve() })
   .catch((e) => { console.log("where did you come from " + e) })

The output from the above is "where did you come from ReferenceError: x is not defined"

grabbag
  • 980
  • 1
  • 15
  • 33
  • FYI, `return Promise.resolve` makes no sense since that is just returning a function reference. Perhaps you meant `return Promise.resolve()`. Plus, there's no point to it either as you can just do `return value;` directly. – jfriend00 Sep 22 '17 at 19:04
  • Use the [Bluebird promise](http://bluebirdjs.com/docs/api-reference.html) library which will capture stack traces of rejected promises. Other than that, the usual way to narrow in on where a rejection is originating is with logging `.catch()` statements closer to where the rejection originates. `.catch(err => {console.log("something useful", err); throw err;});` – jfriend00 Sep 22 '17 at 19:06
  • jfriend00, good catch. I'll update the example. My example works by a side effect of anything returned in a then is automaticaly wrapped in a Promise.resolve. So my example returns a resolved promise a parameter of the function to generate a resolve promise. – grabbag Sep 22 '17 at 19:21

1 Answers1

0

A possible solution would be to make a resolver wrapper for promises, that accepts a reject message.

const resolver = (resolveItem, rejectMessage) => {
  return Promise
  .resolve(resolveItem)
  .catch(err => Promise.reject({...err, myMessage: rejectMessage}))
}

Promise.resolve()
.then(() => { return resolver(function1(a, b, c), "1") })
.then(() => { return resolver(function2(a, b, c), "2") })
.then(() => { return resolver(function3(a, b, c), "3") })
.catch((e) => { console.log("I came from " + e.myMessage) })
Prasanna
  • 4,125
  • 18
  • 41
  • This would require wrapping each promise. Not much different from putting a catch on every promise. I was hoping for some global thing to tell nodejs, rather then turn an exception into a reject with a small cryptic message, create a traceback. – grabbag Sep 22 '17 at 20:00
  • `Bluebird` has it http://bluebirdjs.com/docs/api/promise.longstacktraces.html – Prasanna Sep 22 '17 at 20:06
  • I found in the doc the following. but only works if there is no catch at all.process.on('unhandledRejection', (reason, p) => { console.log('******Unhandled Rejection at:', p, 'reason:', reason); // application specific logging, throwing an error, or other logic here }); – grabbag Sep 22 '17 at 20:10