Node giving UnhandledPromiseRejection warning, whe

2019-07-24 13:40发布

问题:

I'm using node-libcurl. I've got a little module in which I have a queue for curl requests. Here's what the function looks like to actually make the curl request:

const Curl = require('node-libcurl').Curl;

let timeoutCount = 0;
function _getOData(url) {
    const curl = new Curl();
    return new Promise((resolve, reject) => {
        curl.setOpt(Curl.option.URL, url);
        curl.setOpt(Curl.option.HTTPAUTH, Curl.auth.NTLM);
        curl.setOpt(Curl.option.SSL_VERIFYPEER, false);
        curl.setOpt(Curl.option.SSL_VERIFYHOST, false);
        curl.setOpt(Curl.option.POST, 0);
        curl.setOpt(Curl.option.HTTPHEADER, ['Accept: application/json']);

        let done = false;

        curl.on('end', function (statusCode, body, headers) {
            done = true;
            const retObj = JSON.parse(body);
            resolve(retObj);
            curl.close();
        });

        curl.on('error', function (e) {
            done = true;
            reject(e);
            curl.close();
        });

        curl.perform();

        setTimeout(() => {
            if (!done) {
                timeoutCount++;
                reject(new Error(`request timed out: ${timeoutCount}`));
            }
        },1000*10);
    })
}

I kept getting this error in the console: (node:26616) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 6): Error: request timed out -- so I added the the timeoutCount because I was certain I was catching all Promise errors, despite getting this warning.

Every single call to the _getOData function happens inside the queue logic, specifically this code is the only code to call _getOData:

        const p = _getOData(nextObj.url);
        p.then(nextObj.cb);
        p.catch((e) => {
            if (e.message.includes("request timed out")) {
                queue.add(nextObj.url, nextObj.cb, nextObj.ecb);
                return true;
            } else {
                nextObj.ecb(e);
                return false;
            }
        });

So I set a breakpoint after e.message.includes("request timed out") and it hits there every single time a request timed out error happens, so I KNOW FOR SURE there are no 'unhandled promise rejections'. Every single promise rejection goes through that catch. I inspect the variable when it breaks there to make sure that the timeoutCount is there, and it always is, and then it still always gets logged to the console as an unhandled promise rejection.

What's going on here?

回答1:

You're probably catching the reject on the queue and not on the stack. You get that error (warning) with the following code:

var p = Promise.reject("hello world");//do not catch on the stack
setTimeout(
  x=>p.catch(err=>console.log("catching:",err))//caught error on queue
  ,100
);

If you're going to catch the reject on the queue then you can do the following:

saveReject = p =>{
  p.catch(ignore=>ignore);
  return p;//catch p but return p without catch
}
var p = saveReject(Promise.reject("hello world"));//creating promise on the stack
setTimeout(
  x=>p.catch(err=>console.log("catching:",err))//caught error on queue
  ,100
);

Information about queue and stack can be found here.