Reputation: 914
I'm not sure if "fail-fast" is the best way to describe this methodology, but ever since I started to learn about programming I have always been taught to design functions like this:
function doSomething() {
... // do error-prone work here
if (!allGood) {
// Report error, cleanup and return immediately. Makes for cleaner,
// clearer code where error-handling is easily seen at the top
...
return;
}
// Success! Continue on with (potentially long and ugly) code that may distract from the error
}
As such, I'm trying to call a promisified function like so:
doSomethingAsync(param).catch(err => {
console.error(err);
}).then(() => {
// Continue on with the rest of the code
});
But this gives me behaviour akin to the finally
block of a classic try...catch...finally
statement, i.e. the then()
block will always be called, even after an error. Sometimes this is useful, but I rarely find myself needing such functionality (or try...catch
statements in general, for that matter).
So in the interest of failing as quickly and clearly as possible, is there a way that I can make the second example above work in the way that I expect (i.e. then()
is only executed if catch()
wasn't, yet a single catch()
will still catch all errors raised by doSomethingAsync()
)?
Upvotes: 1
Views: 1377
Reputation: 371138
If you use async
and await
instead of .then
, you can effectively wait for the Promise to resolve (or reject), and if it rejects, return early:
(async () => {
try {
await doSomethingAsync(param);
} catch(err) {
console.error(err);
return;
}
// Continue on with the rest of the code
})();
const doSomethingAsync = () => new Promise((resolve, reject) => Math.random() < 0.5 ? resolve() : reject('bad'));
(async () => {
try {
await doSomethingAsync();
} catch(err) {
console.error(err);
return;
}
console.log('continuing');
})();
That's what I'd prefer. You can also use the .then(onResolve, onReject)
technique, though it's usually not recommended:
function onReject(err) {
console.log(err);
};
doSomethingAsync(param).then(onResolve, onReject);
function onResolve() {
// Continue on with the rest of the code
}
const doSomethingAsync = () => new Promise((resolve, reject) => Math.random() < 0.5 ? resolve() : reject('bad'));
function onReject(err) {
console.log(err);
};
doSomethingAsync().then(onResolve, onReject);
function onResolve() {
console.log('continuing');
}
This will have onReject
only handle errors thrown by doSomethingAsync(param)
. If your onResolve
can throw inside its body as well, then you'll have to chain another .catch
onto it (which will start to look a bit messy - it's usually nicer to catch errors in just one place)
Upvotes: 1