question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

With asCallback and finally, Unhandled Rejection is emitted.

See original GitHub issue
  1. What version of bluebird is the issue happening on? Tested on 3.4.1, 3.3.0, and 2.10.2.

  2. What platform and version? (For example Node.js 0.12 or Google Chrome 32) Mac OS X, tested with Node 4.4.7 and 6.3.1.

  3. Did this issue happen with earlier version of bluebird? Yes, see answer to 1.


promise.js

'use strict';

var Promise = require('bluebird');

process.on('unhandledRejection', function() {
  console.log('unhandledRejection');
})

Promise.reject('foo').asCallback(() => {
  console.log('asCallback');
}).finally(() => {
  console.log('finally');
});

output

$ node promise.js
asCallback
finally
unhandledRejection

Using the code snippet above, you’ll see that unhandledRejection is emitted, despite the asCallback which will handle the rejection. I would expect the output to be just this:

expected output

$ node promise.js
asCallback
finally

If you remove the .finally bit so the promise sequence looks like this:

Promise.reject('foo').asCallback(() => {
  console.log('asCallback');
});

Then the unhandledRejection event is no longer emitted:

$ node promise.js
asCallback

This seems correct to me, but is inconsistent with the .finally case.

Issue Analytics

  • State:open
  • Created 7 years ago
  • Comments:10 (6 by maintainers)

github_iconTop GitHub Comments

1reaction
NatalieWolfecommented, Aug 11, 2016

I can understand the optimization of not creating a promise when cb is not a function, but when cb is a function which will handle the rejection, it seems like a bad idea. I agree that using a callback and chaining off the promise is a strange use case, but it is one that I have now encountered in code that is not my own and that I can not change.

By having asCallback act differently than any other method it breaks expectations of how the promise chain should resolve. It means that without knowing the finer details of its execution, what looks like a normal chain of promises will resolve in unexpected ways.

The way Promise.reject(...).asCallback(...).finally(...) resolves is the same as this:

var p = Promise.reject('foo');
p.then(() => console.log('resolved'), () => console.log('rejected'));
p.finally(() => {
  console.log('finally');
});

In the latter case it is explicitly obvious why that would cause an unhandled rejection, you have an explicitly branching promise and one of those branches does not handle the rejection. In the former asCallback case, the code is still branching, but as a hidden side effect. No other method does that.

1reaction
ben-pagecommented, Aug 10, 2016

That’s because asCallback is designed to make a function that can accept a callback or return a Promise. If you continue the Promise chain from asCallback (with finally, or then, etc), it thinks you want the Promise version.

Look at this example:

function CallbackOrPromise(cb) {
    return Promise.reject(new Error('Reject!'))
        .asCallback(cb);
}

//callback version
CallbackOrPromise(function(err) {
    console.log('Error From Callback: ' + err.message);
});

//promise version
CallbackOrPromise()
    .catch(function(err) {
        console.log('Error From Promise: ' + err.message);
    });

What you are doing is like calling CallbackOrPromise without a catch. This produces an Unhandled rejection.

CallbackOrPromise()
    .then(function() {
        console.log('then');
    });
Read more comments on GitHub >

github_iconTop Results From Across the Web

Unhandled Rejection (TypeError): callback is not a function
You have loadOptions={loadData('Parameter I want to pass')} but loadData requires you to pass it both a string and a valid function.
Read more >
Promise-toolbox - npm.io
This library provides an implementation of CancelToken from the cancelable promises specification. A cancel token is an object which can be passed to ......
Read more >
Node.js Error Handling Best Practices - Sematext
Learn what is Node.js error handling and why do you need it. From using middleware to catching uncaught exceptions, discover the best ways ......
Read more >
asCallback - Bluebird JS
When this promise is either fulfilled or rejected, the node callback will be called back with the node.js convention where error reason is...
Read more >
promise-toolbox - npm Package Health Analysis - Snyk
Downloads are calculated as moving averages for a period of the last 12 months, ... will not emit an unhandled rejection error if...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found