Promise Unhandled rejection null

80 views
Skip to first unread message

Andrea Di Mario

unread,
Dec 18, 2015, 3:53:43 AM12/18/15
to bluebird
Hi, i've this code:

module.exports.run = function(event, context, cb) {
  myclass.queryAsync(...)
  .then(function (results) {
    if (results.field === "test") {
      throw "error";
    } else {
      return cb(null, "success");
    }
  })
  .catch(function (err) {
    return cb(err)
  });
};

for promise i'm using bluebirdjs and i've attached this code to a mocha test. If function give back a success, the test passes without problems. If the test has errors, the stdout give back: Unhandled rejection null, the mocha test goes on and then stops with exceeded timeout limit.

My mocha test:
  before("Description", function(done) {
    require('path').run(event.options, {}, function (err, results) {
      if (err) {
        throw err;
      }
      done();
    });
  });
  

Some suggestions about that?
Thanks for your time.
Best regards

Nate Schmolze

unread,
Dec 20, 2015, 9:16:43 PM12/20/15
to bluebird
Okay, this has an interesting execution path:
  1. .queryAsync experiences an error.  Since it's promise-based, it skips over the .then function, and hits .catch.
  2. .catch calls the callback with the error.
  3. The callback provided in the test checks for an error, and throws it.  This ends the callback function, and passes control back to .catch.
  4. .catch doesn't have any try/catch handlers inside of it, so the thrown error propagates up to the Promise code, which catches it.
  5. There is no more error handling after .catch, so bluebird detects that the thrown error was never caught and logs it (by default)
Does that make sense?  This is conceptually similar to rethrowing an error from inside of a synchronous catch statement.  .catch will handle any error that was thrown in the promise chain before it, but if you throw something inside of .catch, the resulting promise will be be rejected once more.

As an aside, there's a lot of switching back and forth between callbacks and promises in the above code; is that intentional?  If you're defining your own API, you may consider making the run function return a promise instead of asking for a callback.  I'd do something like this:

module.exports.run = function(event, context) {
  return myclass.queryAsync(...)
  .then(function (results) {
    if (results.field === "test") {
      throw "error";
    } else {
      return "success";
    }
  });
};

...
 
before("Description", function() {
  return require('path').run(event.options, {}); 
  // mocha will pass the test if the promise is resolved, or fail if it is not.
  // if you needed to catch the error manually however, this is where you would do it.
});

 If you need your API to support both callbacks and promises, then check out the function .asCallback.  It allows APIs to be created that accept either promises or callbacks:

module.exports.run = function(event, context, cb) {
  return myclass.queryAsync(...)
  .then(function (results) {
    if (results.field === "test") {
      throw "error";
    } else {
      return "success";
    }
  }).asCallback(cb);
};

...
 
before("Description", function(done) {
  return require('path').run(event.options, {}, function(err, results) {
    done(err);
  }); 
});

 Hope that helps.

Andrea Di Mario

unread,
Dec 21, 2015, 8:29:04 AM12/21/15
to bluebird
Hi, thanks for your reply, i've modified my mocha test with this if:
if(err) done(err)
else done()
And now the error "Unhandled rejection null" not appears and the mocha test not exceeds the timeout.
Thanks for your time.
Best regards

Nate Schmolze

unread,
Dec 21, 2015, 12:56:42 PM12/21/15
to bluebird
np, glad it worked out :-)
Reply all
Reply to author
Forward
0 new messages