When you pass two callbacks to .then()
as in .then(fn1, fn2)
, then ONLY ONE of them will get executed based on the state of the parent promise. Throwing in fn1 will NOT cause fn2 to execute.
If you want your error handler to be executed when you throw
in a .then()
handler, then use a .catch()
after it as in:
.then(fn1).catch(fn2)
In that case, throwing in fn1
will cause fn2
to execute.
Why is throw statement needed in the first callback in then(),
In your specific example, the throw is to turn the case when response.ok
is not true into a promise rejection. fetch()
by default only rejects when there's an actual network error. A 400 or 500 status does not cause a rejection. As far as fetch()
is concerned, any response from the server, even a 4xx or 5xx response is considered "success" and results in a resolved promise, not a rejection.
So, the point of your throw
is to turn those 4xx and 5xx cases into a rejection. Of course, you don't have any code in your example that will catch that rejection because you don't show a subsequent .catch()
or subsequent .then()
with the second argument.
since rejected case will be handled in the second callback?
Your throw
won't be handle in your second callback. And, a !response.ok
won't be handled by your second callback either.
In my opinion, this whole issue of 4xx and 5xx responses not being a rejection is a primary benefit to using other libraries such as axios()
or got()
as it prevents you from having this extra code every time. Of course, you could also make your own wrapper utility function that you use instead of fetch()
. In fact, I was bummed that nodejs was making the fetch()
interface a standard interface because IMO this is a usability miss with the way this interface works. It leads to either faulty code when people don't check and handle !response.ok
or it results in extra code all the time to do so. Libraries like axios()
or got()
are configurable in this regard with a default to reject upon 4xx and 5xx response.