Promise.prototype.finally
developers.google.com
developers.google.com
[1]: https://github.com/tc39/proposal-promise-finally [2]: https://github.com/tc39/proposals/blob/master/README.md [3]: https://tc39.github.io/process-document/
I always chain a `then` after `catch` in these situations.
fetch(...)
.then( response => data.response = response )
.catch( error => data.error = error )
.then( () => closeThatLoader() )The point is, there is no way to do .catch().then() and throw the error unless you do some hideous type checking hack cludge. Hence the need for .always().
Also, I think `finally` makes your code easier to read. I always put the same kind of cleanup logic in there, everyone on the team knows what to expect in that block.
fetch(...)
.then(response => {
closeThatLoader();
return success(response);
})
.catch(error => {
closeThatLoader();
throw error;
});The fact that catching a promise marks it as resolved and triggers subsequent "then"s rather than "catch"s. It means that every callback needs to be aware of every other callback and their own place in the order, so that only the last catch statement doesn't rethrow the exception.
Something like $.Deferred() allows you to set 10 "fail" callbacks independently, which helps a lot when the original promise is generated by a deeply nested method and different stages of the chain add their own handling.
(It's more apparent too in the async/await space where catch is even literally try {} catch {}.)
In my specific case I'm passing a lot of promises to user-made scripts. then/catch seems to make things more brittle. As I said though, I'm new to them.
If you get a chance, particularly play with async/await code somewhere. There's a lot of misconception that async/await replaces Promises or is very different from Promises, but the reality is much closer that Promises were a necessary building block for async/await, and some of the trade-offs in Promise design are there to support async/await, based on work that had already been done in other languages.
Maybe if you try to write some of your work as async/await it might give you insights into your architecture and how to make it feel less brittle.
a
.then(b).catch(bhandle)
.then(c).catch(chandle)
instead of a
.then(aout => b(aout).catch(bhandle))
.then(bout => c(bout).catch(chandle))
which admittedly is pretty ugly in javascript. try {
const response = await fetch(url);
const text = await response.text();
element.textContent = text;
} catch (error) {
element.textContent = error.message;
} finally {
hideLoadingSpinner();
}
and try {
const response = await fetch(url);
const text = await response.text();
element.textContent = text;
} catch (error) {
element.textContent = error.message;
}
hideLoadingSpinner();
?Other than that, this is great. But I don't understand the async/await version
try {
throw new Error("catch me !"); // force try to fail
} catch (catchedError) {
console.log("inside catch");
// throw new Error("hmm");
} finally {
// always executed
console.log("inside finally");
}
// always executed
console.log("after try catch finally");
the finally statement can be useful when another error is thrown inside the catch block, in which case you have more serious problems in your codeIn general the finally { ... } block is useful because it is guaranteed to execute after the try/catch (if the program has not exited), where as the next line after the try/catch is not, e.g., the try/catch returns, or the catch block throws.
(()=>{try {return 42} finally {console.log('you will see this')}})()
The fn body returns 3, but also the "finally" executes first and you get the console.log. Same with:
(()=>{try {throw 42} finally {console.log('you will see this')}})()
Let's not assume that polyfills are free. As far as I can tell [0], you need two Babel transforms to enable support across browsers, with the generator polyfill running you about 20kb.
Better late than never, I suppose.
Personally I like the “defer” method, where closing actions can be clear and front-loaded in the function definition.
`result=mayBePromiseOrResultWhoKnows()`
instead of
`go nowThisSyncMethodIsAsync()`
result = await maybePromiseWhoCaresIUsedAwait();
You can use await without knowing if the function you called returns a promise or not. This works fine: result = await 3;Or you may end up with obscure bugs, when you expect a sync method or worse, when a sync method changes to async in the next api version(happened in real world!)
So, the grandparent's complaint is about JavaScript being a dynamic language, async/await doesn't fix this issue or make it any worse.
$ node --harmony_promise_finally -e '
Promise
.resolve()
.finally(() => console.log("foo"))
.finally(() => console.log("bar"));
'
foo
barRealistically, if you are shipping software in the real world where it could run on older browsers, you do need to use something like bluebird just to get uniform support. Not to mention things like maps/each/joins/timeouts that you will likely need for anything non-trivial.