0

Hi everyone!

I use Node.js v8.5.0. And this is my code in Node.js (simplified):

    // function that returns promise
    const request = (url) =>
      new Promise((resolve, reject) => {
        superagent
          .get(url)
          .end((err, res) => {
            if (err || !res.ok) {
              reject(err);
              return;
            }

            resolve(res);
          })
      })

   // function that add .then and .catch to promise   
   const to = promise =>
    promise
    .then((data) => [null, data])
    .catch((err) => [err]);

   // making request 
   let [err, result] = await to(request());

When i do request and some error occurs .catch function doesnt catch rejected value and i get error like Unhandled Promise Rejection. But, in fact I added .catch function to promise.

Does anyone know what is wrong here? Thanks for help!

Emil
  • 671
  • 1
  • 6
  • 22

2 Answers2

2

A superagent request already returns a promise so use that instead

const request = (url) => superagent.get(url).then(res=> {/*transform res**/ return res})
charlietfl
  • 170,828
  • 13
  • 121
  • 150
  • …which probably is also the reason why the unhandled rejection occurs - this superagent promise is the one that gets rejected and not handled, not the `new Promise` which indeed has a `.catch` chained to it. (Of course this sounds like a superagent bug, calling `.end()` should mark the promise as handled). – Bergi Dec 12 '17 at 16:24
  • `.then` function works well in my code. But when error occurs `.catch` function doesnt catch error. This is strange because in fact its added to promise via `to` function. – Emil Dec 12 '17 at 16:33
  • Perhaps you have other anti-pattern promises wrapping something else that also returns promise and as bergi points out it's another promise not in the chain that is unhandled – charlietfl Dec 12 '17 at 16:40
  • I found some explanation about this problem. Read this please https://stackoverflow.com/a/41180264/5441891 Here @daskh-gupta says that : _The difference is that you don't handle .catch(...) as chain but as separate. For some reason Java Script engine treats it as promise without un-handled promise rejection_ – Emil Dec 12 '17 at 17:05
  • Is this a bug in JavaScript engine? What do you think? – Emil Dec 12 '17 at 17:06
  • 1
    But are you not chaining the catch the same way as shown in question? Code in question is not same as second example in link you provided. Your chain is correct – charlietfl Dec 12 '17 at 17:08
  • Yes. Second example is a little bit different but overall code is looks similar. That is, firstly i create new promise anf then i attach `.then` and `.catch` callbacks to it. So, may be here we have another similar bug. – Emil Dec 12 '17 at 17:18
  • Now i started to use promise of superagent instead of creating my own. Now my code looks like this and it works without bugs. `let [err, result] = await to(superagent.get(url))` Thanks for all you help. – Emil Dec 12 '17 at 20:44
0

The code you provided does not have that behavior but I am familiar with the uncaught in promise warning.

If you want to catch an error of a promise later you have to catch it first and return the promise before you catch it.

The following will give you uncaught in promise warning:

var failPromise = val => Promise.reject(val);
var to = async promise => promise.then(val=>[null,val]).catch(err=>[err]);
var p = failPromise(88);
//later you will catch the error
setTimeout(()=>to(p).then(val=>console.log("resolved to:",val)),100);

But if you change it a bit then you won't

var failPromise = val => {
  const p = Promise.reject(val);
  p.catch(ignore=>ignore);
  return p;//return the promise that did not have the catch
};
var to = async promise => promise.then(val=>[null,val]).catch(err=>[err]);
var p = failPromise(88);
//later you will catch the error
setTimeout(()=>to(p).then(val=>console.log("resolved to:",val)),100);

As suggested before; your request method should just return the promise that superagent returns but in such a way that you can catch the reject later without the errors(warnings):

const request = (url) => {
  const p = superagent
    .get(url);
  p.catch(ignore=>ignore);
  return p;
})

If you are wondering why you get uncaught in promise; it is because you catch the rejection in the queue and not in the stack. Stack and queue is explained here.

The example that catches in stack causes no errors in the console but then returns the promise that did not have the catch on it. Depending how far in the queue you are going to catch it it may still give you errors but in code provided it won't.

HMR
  • 37,593
  • 24
  • 91
  • 160
  • 2
    There is no reasons you MUST catch the superagent promise itself. It will get caught in the chain shown in OP code – charlietfl Dec 12 '17 at 17:25
  • @charlietfl code OP posted is obviously not the code that gives him the error he talks about nor does it behave the way OP describes. If OP would have tested provided code then OP would know it doesn't. Updated answer to explain where uncaught promise comes from. – HMR Dec 12 '17 at 17:26
  • Accept that. There's something else op is not showing us – charlietfl Dec 12 '17 at 17:29
  • @charlietfl I actually made a mistake, assigned p to `promise.catch` instead of `promise`, so you could never catch it later (in code that's on the queue). Fixed the problem in updated answer. – HMR Dec 12 '17 at 17:36
  • Thanks for all answers – Emil Dec 13 '17 at 14:57