So I'm using request-promise in a script that I have that loops through a list of urls and fires of requests. Then I want to do something w/ the data received once all the requests are complete.
I have the following:
var rp = require('request-promise');
rp.get({
uri: 'http://httpstat.us/500',
transform: function(body, res){
res.data = JSON.parse(body);
return res;
}
}).then(function(res){
results.push(res.data);
})
.catch(function(err){
should.throw.error.to.console();
var respErr = JSON.parse(err.error);
var errorResult = {
origUrl: respErr.origUrl,
error: respErr
};
results.push(errorResult);
});
As you can see.. http://httpstat.us/500 throws a 500, which causes the .catch() block to be ran. I'm forcing an error. should.throw.error.to.console();
should throw an error to the console, but instead, the script just exits silently w/o any error code (Process finished with exit code 0
).
I'm assuming that request-promise is catching the error from node's http
when a page doesn't come back w/ 2xx code and then passing that back to the catch() callback. But any subsequent errors then end up failing silently. How in the world do I handle this so that the rest of my code will still throw errors properly?
Related GitHub issue
There are two ways in which you can handle errors in your promise chain, either by passing an error handler to then block or using the catch operator.
We must always add a catch() , otherwise promises will silently fail. In this case, if thePromise is rejected, the execution jumps directly to the catch() method. You can add the catch() method in the middle of two then() methods, but you will not be able to break the chain when something bad happens.
To support error handling, Promise objects provide a catch() method. This is a lot like then() : you call it and pass in a handler function. However, while the handler passed to then() is called when the asynchronous operation succeeds, the handler passed to catch() is called when the asynchronous operation fails.
Promise.all fail-fast behaviorPromise.all is rejected if any of the elements are rejected. For example, if you pass in four promises that resolve after a timeout and one promise that rejects immediately, then Promise.all will reject immediately.
What do you mean by "any subsequent errors then end up failing silently"? If the original promise rp
fails, the catch
executes… at the time of failure. Once a promise is rejected, that's it, there can be no "subsequent errors."
Also, should
looks like an assertion (e.g. from chai
) which would suggest that you are trying to test this. Chai's should.throw
doesn't throw an error, it checks that an error has been thrown. If you are testing this, you need to indicate to the test (it
block) that the test is async, not sync — usually by naming & invoking a done
parameter. Otherwise, the request will be sent out, and then before ANY response can be made, the script will synchronously end and no errors will be listened for.
What's more, you are spec'ing that something should throw
to console, but nothing in your code throw
s! If you DID write in a throw
, you should understand that throw
inside a then
or catch
will simply cause the outgoing promise from that handler to be rejected with the thrown value (yes, catch
exports a new promise, just like then
— it is 100% sugar for .then(null, errHandler)
. If you want errors to be re-thrown back into the window, you need to finalize the chain with Bluebird's .done()
promise method, accessed in request-promise via the somewhat arcane .promise().done()
. But even in that case you'd still need to specify that you're doing an async test.
In short, it's not entirely clear what you think some of this code is supposed to be doing, and how it differs from your expectations. Please clarify!
var rp = require('request-promise');
rp.get({ // start an async call and return a promise
uri: 'http://httpstat.us/500',
transform: function(body, res){
res.data = JSON.parse(body);
return res;
}
}).then(function(res){ // if rp.get resolves, push res.data
results.push(res.data);
})
.catch(function(err){ // if rp.get rejects (e.g. 500), do this:
should.throw.error.to.console(); // test if something is thrown (but nothing has been!)
var respErr = JSON.parse(err.error);
var errorResult = {
origUrl: respErr.origUrl,
error: respErr
};
results.push(errorResult); // push an object with some of the error info into results
});
// this line (e.g., end of script) is reached before any of the async stuff above settles. If you are testing something, you need to make the test async and specify when it's complete by invoking `done()` (not the same as ending the promise chain in Bluebird's `.done()`).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With