I have this piece of ES6 code that invokes a java backend. The java backend normally returns status code 200 and a json payload, but sometimes status code 500 and a json payload. For 200 I want to deserialize the json and pass the resulting object up the promise chain. For 500 I want to deserialize the json and throw the resulting object up the promise chain, i.e. have it hit the catch blocks.
The following code does almost what I want:
invoke(className, methodName, args) {
return this.httpClient
.fetch('/api/' + className + "/" + methodName,
{
method: 'POST',
body: json(args)
})
.catch(response => {
// Function A
throw response.json();
})
.then(response => {
// Function B
return response.json();
});
}
this.invoke("TestService", "testMethod", {a: 1, b: 2})
.then(response => {
// Function C
console.log(response); // prints the actual json object which I expect
}).catch(response => {
// Function D
console.log(response); // prints: [object Promise]
});
I've been working at this for a while now, but I'm having trouble explaining to google what my problem is.
Question: Why does returning a promise 'unwrap' the promise for the next function, but throwing a promise passes the promise itself into the next function?
Is there any way I can achieve what I want, which is for function D to get the 'unwrapped' object just like function C?
The reason you get the promise in catch
callback, is that this is by specification.
For returned values within a then
or catch
callback, the rule is that that promise must resolve before the outer promise resolves, and that the resolved value should be the value promised by the returned promise. From the Promises/A+ specs 2.2.7.1:
If either
onFulfilled
oronRejected
returns a valuex
, run the Promise Resolution Procedure[[Resolve]](promise2, x)
.
Chapter 3 in that specification further explains what that means.
However, this is not true for thrown exceptions, as can be seen in point 2.2.7.2:
If either
onFulfilled
oronRejected
throws an exceptione
, promise2 must be rejected withe
as the reason.
No attempt is made to recognise e
as a promise nor to wait for its resolution. It is thrown as is, and that will be what you get in the next catch
.
The solution is thus to return a promise, but a promise that will throw the resolved value (not a promise):
return response.json().then(data => { throw data });