I am starting with E6 Promises. I like them very much, but there is a crucial concept around error handling that I don't understand and would love some clarification on.
Let's assume the following simple function that returns a promise:
function promiseString(str, timeout, doResolve) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (doResolve) {
resolve(str);
} else {
reject(new Error("Rejecting " + str));
}
}, timeout);
});
}
It is pretty straightforward, just returns a promise for the string that was passed to it, and causes that promise to be resolved or rejected (based on the third argument) in "timeout" milliseconds.
I can consume this completely as expected as follows:
promiseString("One", 100, true)
.then((str) => { console.log("First then is " + str); return promiseString(str + " two", 100, true); })
.then((str) => { console.log("Second then is " + str); return promiseString(str + " three", 100, true); })
.then((str) => console.log(str))
.catch((err) => console.error(err));
If alter the third argument to from "true" to "false" in any of the calls in this chain, my error is caught as expected and send to console.error().
However, now imagine the following (similarly silly) function for constructing a promising object:
function DoublePromiser(str1, str2, doResolve) {
this.promise = new Promise((resolve, reject) => {
promiseString(str1, 100, doResolve)
.then((s1) => promiseString(s1 + str2, 100, doResolve))
.then((s2) => resolve(s2));
});
}
Imagine now that I consume this code as follows, with everything resolving and nothing rejecting, (doResolve is set to true):
var dp = new DoublePromiser("Big", "Promise", true);
dp.promise
.then((s) => console.log("DoublePromise: " + s))
.catch((err)=>console.log("I did catch: ", err.message));
As would be expected, I see the following in the console:
DoublePromise: BigPromise
However, now I alter the consuming code, setting doResolve to "false" (which causes my promise routine to reject):
var dp = new DoublePromiser("Big", "Promise", false);
dp.promise
.then((s) => console.log("DoublePromise: " + s))
.catch((err)=>console.log("I did catch: ", err.message));
Because of my understanding of how errors should "bubble up", I would expect the console to log as follows:
I did catch: Rejecting Big
But it does not. Instead, the console shows an uncaught error:
Uncaught (in promise) Error: Rejecting Big
I only get what I expect (and desire) if I add a catch to the end of the chain in the DoublePromiser, like this:
function DoublePromiser(str1, str2, doResolve) {
this.promise = new Promise((resolve, reject) => {
promiseString(str1, 100, doResolve)
.then((s1) => promiseString(s1 + str2, 100, doResolve))
.then((s2) => resolve(s2))
.catch((err) => reject(err)); // ADDING THIS TO MAKE IT WORK
});
}
Now I get what I expect, the error is not uncaught. But this seems counter to the whole idea that errors bubble up, and it seems weird to catch an error just to re-reject the same error.
Am I missing a way of getting this to work simply?
Am I missing some fundamental concept?