2

I have this promise chain.

com.openPort(port).then(port => {
                        _.pTimeout(3000, com.sendPort(port, NCD.gen(args.cmd)))
                            .then(received => {
                                console.log('complete response: ', NCD.parse(received));
                                Debug.L1('resolved num data listeners: ', port.listenerCount("data"));
                            })
                    })
                    .catch(function(e) {
                        console.log('error: ', e)
                    });

and I'm testing the timeout promise by sending a bogus command that will make the sendPort promise be unresolved. The timeout promise wins the race throwing a reject but a warning comes before the .catch handles the rejection.

here's the timeout promise race

pTimeout: function(timeout, promise) {
        return Promise.race([
            promise,
            new Promise(function(resolve, reject) {
                setTimeout(function() {
                    reject('\nTimed out');
                }, timeout);
            })
        ]);
    }

console shows

  (node:9616) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): 
  Timed out

you can see after the warning the .catch putting "Timed out" to the console so it was handled...albeit improperly??

I'm using node 6, which it seems by other posts, now warns if it's not handled in the first tick. I can't grok how to fix this from those. How should this be handled? I tried putting a .catch right after the timeout promise but still get the warning before the .catch.

DKebler
  • 1,216
  • 1
  • 15
  • 27

1 Answers1

4

The promise returned by _.pTimeout() is orphaned and rejections are not handled. To handle them, you either need a .catch() on that specific promise or you need to add a return so that it is chained to the parent promise so it will get caught by the higher level .catch(). I'd suggest returning/chaining it since you rarely wanted a promise to just proceed at its own pace and not be connected at all to the parent promise:

com.openPort(port).then(port => {
    return _.pTimeout(3000, com.sendPort(port, NCD.gen(args.cmd))).then(received => {
        console.log('complete response: ', NCD.parse(received));
        Debug.L1('resolved num data listeners: ', port.listenerCount("data"));
    });
}).catch(function (e) {
    console.log('error: ', e)
});
jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • yes that worked thx. Still if I understood why that is orphaned I'd avoid this again in the future. Is it because it sits "inside" the .then of the first promise resolution? If that's so as I nest promises they must all be prefaced with return or they (and any "inside" them) will be orphaned? – DKebler Oct 17 '16 at 06:52
  • @DKebler - Yes. There is no magic in promises. They don't know anything about what's in a `.then()` handler. So, if you have another promise inside of there, the only way to chain it to the parent promise is to return it from the `.then()` handler. That makes the parent promise then wait for the child promise to resolve before the parent promise also resolves. If you don't return anything from the `.then()` handler, then the parent promise is completely unaware of the child promise and the child promise is left on its own. – jfriend00 Oct 17 '16 at 07:17
  • I get it now! they need a way to bubble up to that top .catch. This also helps me to make better sense of this very good article on flattening a chain which is probably overkill for just one nest like this, but it's clear returning a promise is different than returning some value. Thx https://github.com/ThomasBurleson/angularjs-FlightDashboard – DKebler Oct 17 '16 at 17:23