8 ms·
> In either case we need to call hideLoadingSpinner(). Until now, we had no choice but to duplicate this call in both the then() and the catch() block. I alway
by drinchev 9y ago
> In either case we need to call hideLoadingSpinner(). Until now, we had no choice but to duplicate this call in both the then() and the catch() block.
I always chain a `then` after `catch` in these situations.
fetch(...)
.then( response => data.response = response )
.catch( error => data.error = error )
.then( () => closeThatLoader() )
- Kiro 9y agoYes, trying to understand what the point of .finally is when a subsequent .then after .catch seems to achieve the same thing. What am I missing?
- eknkc 9y agoIf you are returning that promise, you'll need to handle both then and catch so the caller can chain their own catch.
- untog 9y agoA final .catch().then() swallows the error, .always() does not.
- joshribakoff 9y agoCatch "swallows" errors by design. Unless you re throw. chaining another then has no effect on the behavior of a previous catch.
- untog 9y agoRight, but in the context of the OP's question you'd need the second .then() to mirror what .always() is doing. 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().
- JSDave 9y agoYea, the `catch` would probably have to set an 'errors' object on the response. The following `then` would then decide whether or not to throw an error based on that. Not pretty. 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.
- bbatha 9y agoIf you rethrow in the catch the next then won't get executed.
- Kiro 9y agoWill finally be executed between the throw and whatever catches it or after?
- runarberg 9y agoAnother upside of the proposal is that if you need to reuse the fetch promise somewhere else it will retain the reject status if the promise fails. The proposal is more akin to: fetch(...) .then(response => { closeThatLoader(); return success(response); }) .catch(error => { closeThatLoader(); throw error; });
- riquito 9y agoYou may want to do something _and then_ throw the error, to let it reach the caller. In your example it would mean to run "closeThatLoader" and later throw the error. It's really cumbersome without `finally`
- semperdark 9y agoAm I the only one that really dislikes the "catch" behavior? 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.
- WorldMaker 9y agoThe catch behavior mirrors try {} catch {} blocks. If you don't need a catch, don't catch, and let it bubble up. Try to keep the things you catch to a bare minimum. The rethrow decision is largely the same for Promises as try {} catch {} blocks, too. (It's more apparent too in the async/await space where catch is even literally try {} catch {}.)
- semperdark 9y agoThanks for the reply. I guess my contention as someone just starting to use vanilla promises is that it feels like try/catch isn't the appropriate metaphor to use here. 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.
- WorldMaker 9y agoThat's totally fair. There are learning curves involved and sometimes tradeoffs aren't entirely obvious why they were made. 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.
- mathias 9y agoThat’s not equivalent though — in the article’s example, imagine `element` is `undefined`, for example. `then()` wouldn’t be called in that case.