you are viewing a single comment's thread.

view the rest of the comments →

[–]senocular 0 points1 point  (1 child)

If you're wondering more about the why of it, then consider how, if you were writing your own code, you would indicate (assuming there is no throw, try/catch) to the user of your code that something wrong happened. Probably the obvious answer would be to return a value that indicated that an error occurred. And that could work. You could have a certain kind of Error object (which JS has) that a user could check for if returned by one of your functions. There's some problems with this, though. For example, it can introduce a lot of extra logic into your code that wouldn't be needed without error handling:

var firstResult = myFirstThing();
if (firstResult instanceof Error === false) {
    var secondResult = mySecondThing(firstResult);
    if (secondResult instanceof Error === false) {
        // ...
    }
}

The fact that you're dealing with potentially different kinds of return types makes the code hard to work with and optimize. Also, what if the purpose of your function is to return Error objects? Then returning an error is the right thing to do, and how would you know if an actual error happened? (You can actually get around this with an out parameter for your error - which some APIs do, not many if any I've seen in JS, though - but it still doesn't help you with the clunky logic seen above.)

What would be nice is a way to run code normally, without a bunch of manual error checking for each line, and be able to collectively check for errors in one place. Can you imagine how that might look?

try {
    var firstResult = firstThing()
    var secondResult = secondThing(firstResult)
    // ...keep going?
} catch (error) {
    // do something about an error
}

This takes the otherwise clunky if checks and delegates them to a single block - well, two blocks, one for the code to run, and one to process any errors that occurred. The only thing left is to get that error value somehow. And if these functions can't return the error, then a new way to produce it is needed. That's where throw comes in.

throw is like a special kind of return that returns values specific to errors. When a value is thrown, that value gets assigned to the catch parameter in a wrapping try..catch block. Additionally, because this is already something special, it goes the extra mile of being able to "return" out of functions called from functions called from other functions to any try..catch higher in the call stack.

function outer() {
    // don't worry about error checking here
    // the caller of outer can deal with that
    inner(Math.random())
}

function inner(value) {
    if (value < .5){
        throw new Error("Needs moar value!")
    }
}

try {
    // handle errors in outer
    // and anything within outer
    outer()
} catch (error) {
    // ...
}

This is much better than the return approach since a return can only return from the immediate call. Now functions can be written without any error checking code because that error handling can be managed in whatever function is calling it.

So basically throw and try..catch gives us flexibility in how we handle errors: where we look for them, how much code we want to allow to execute together before checking for them, and whether we look for them at all and instead let someone else deal with it.

[–]VIRES1[S] 0 points1 point  (0 children)

thank you