DEV Community

Discussion on: Better error handling with async/await

 
ironsavior profile image
Erik Elmore • Edited

Assuming user fails with a
rejection, user variable will
be assigned an Error object.
Without the user data whats the
point of calling
getFriendsOfUser(user) and
getUsersPosts(user) with an
Error object?

user will not be assigned to an instance of Error and getFriendsOfUser() will not be called in the case where getUser() rejects because await will cause the program to throw out of userProfile(). The error will propagate upward from the awaiting function and will have a message indicating the getUser() call failed.

I would caution you against handling all errors where they occur. You're not necessarily wrong to do that, but be careful not to use that as a hard and fast rule everywhere. Errors should be handled only where the program should take a specific action. This will vary on a case by case basis. In this case, the specific action is to swap one error for another, (but the error is not otherwise handled).

Before I make my next point, I want to say that I like what you're trying to do and I appreciate that you are giving serious thought to patterns that implement exception policy. I wish more devs did that. Don't stop thinking about ways to abstract away and standardize exception handling behavior because every program has that problem.

My code and yours more or less do the same two things: replaces a low level error with another containing context about userProfile()'s intentions; and causes early exit of userProfile(). What's true of one program's error handling behavior is true of the other in terms of outcome.

The caller does not have to check the return value of userProfile() because it's using conventional error propagation paths. This means the caller could use try/catch within an async function that awaits the call to userProfile() or by using .catch() on the promise returned by userProfile(). The caller's option to not handle the error and allow the error to continue propagating normally is also preserved.

The main problem with your proposal is that it defeats a major benefit of using async function, which is being able to write async code that is not cluttered by explicit error handling.

This benefit can be seen in my version because the body of userProfile() contains no explicit error handling, contains no branching (objectively less complex code), and the errors propagated say what userProfile() was doing at the time of the error.

My version could arguably be improved by creating the decorated versions of getUser() (and the others) in the body of userProfile() instead of at program initialization and adding some dynamic context to the error messages (like user name or whatever is useful to capture in the log).

Thread Thread
 
sobiodarlington profile image
Sobio Darlington

Your approach is also good.

I understand your intention from this response.

When I tested your else_throw helper with a promise rejection, it returned and error object instead of throwing, which was the reason for my response. Unless I didn't test properly.

If it throws as expected then your approach will be a great alternative.

Thread Thread
 
ironsavior profile image
Erik Elmore

I must have forgotten to have it throw from the .catch() callback. I intended for it to throw.

Thread Thread
 
sobiodarlington profile image
Sobio Darlington

Yeah. That should be it.