JS: Throw Try Catch Finally
Throw, try, catch, finally
keywords
throw,
try,
catch,
finally,
are for dealing with errors.
often
known as
“exception handling”.
Here is a typical usage syntax:
try { // do something here that that might throw. or throw yourself here throw "XYZ"; } catch (abc) { // abc is a parameter. its value is from throw console.log(abc); // prints XYZ } finally { // the finally if exist, always runs console.log("Finally block run."); } // XYZ // Finally block run.
How to use “throw”, “try/catch/finally”
The syntax of “throw” is:
throw expr;
The syntax of “try/catch/finally” is any of the following:
try {body} catch(e) {body}
try {body} catch {body}
try {body} catch(e) {body} finally {body}
try {body} finally {body}
When the “throw” statement is run, it redirect code execution to a outer “catch” block of a “try catch finally” statement. Then, run the “finally” block if there is one.
If no “try catch finally” is found, JavaScript stops running and prints the expression passed by “throw”.
The purpose of “try” block is just to contain “throw” (or contain function calls that may “throw”.).
When the “try catch finally” is run, code in the “try” block is executed. If throw happens in “try” block, the “catch” block is run, else skipped. The “finally” block (if any) is always run.
try { console.log(3); } catch (e) { console.log(4); } finally { console.log(5); } // result: // 3 // 5
The “throw” and “try/catch/finally” block can be used without each other. But, typically, “throw” is used inside a “try” block. And you should do so in your code.
The throw statement
throw is like goto. It moves the execution to another place in code. The syntax is this:
throw expression;
// example of throw in a function, caught outside of the function function ff() { throw 4; } try { ff(); } catch (ee) { console.log(ee); }
When “throw” is called, execution jumps to the nearest outer block of catch in a “try/catch/finally” block. If the nearest outer block is a function block, then JavaScript tries to find the outer “catch” at where the function is called.
It repeats the process of jumping to the nearest outer block to find a “try/catch/finally”.
If no “try/catch/finally” is found, it's a error, usually JavaScript stops running.
If a “try/catch/finally” is found, the program flow continues at the “catch” block, and the argument of “throw” is passed to the parameter of “catch”.
// throw can be run by itself throw 3; // this is un-catched throw. // js exits and prints 3
// throw in a try/catch block try { throw 3; } catch (e) { console.log(e); } // exits normally. // result is printing 3
// throw in a try/catch block try { if (false) { throw 3; } } catch (e) { console.log(e); } // throw is never executed
The try statement
The try statement encloses a block of code in which an exceptional condition can occur, such as a runtime error or a throw statement. The catch clause provides the exception-handling code. When a catch clause catches an exception, its CatchParameter is bound to that exception.
ECMAScript 5.1 §12#sec-12.14
Here is a example of “try”, trying to call a function that may not exist.
try { yyy(); } catch (e) { console.log("aa"); } console.log("bb"); // result is printing aa then bb // without the try block, calling a non-existent function will exit abnormally, and bb won't be printed
Finally override
A return/throw in finally overrides a pending return or exception from try/catch.
function doIt() { try { throw "try"; } catch { throw "catch"; } finally { return "finally"; // swallows the throw } } doIt(); // "finally"
Error object
The throw is often used with a error object.
That is, in throw expr;, the expr is a error object.
// throw an error object try { throw new Error("xyz is wrong."); } catch (ee) { console.log(ee); }
However, Error object in JavaScript is independent of the “throw/try/catch” statement.
- You can use “throw” to throw something that's not a error object.
- You can also use a error object without any of the {throw, try, catch, finally}.
Write a tutorial on js throw try catch finally
write a tutorial on js throw try catch finally
ai answer
JavaScript Tutorial: throw, try, catch, and finally
JavaScript uses exceptions for error handling. When something goes wrong, you can throw an error. You wrap risky code in a try block so that if an error occurs, execution jumps to a catch block instead of crashing the program. A finally block always runs afterward — whether an error happened or not — which makes it ideal for cleanup.
This tutorial covers the syntax, how control flow works, practical examples, and best practices.
1. the throw statement
throw immediately stops the current function and passes control to the nearest catch (or terminates the program if nothing catches it).
throw expression;
You can throw any value (string, number, object), but you should almost always throw an Error (or a subclass) so you get a stack trace and a consistent .message / .name.
function getRectArea(width, height) { if (isNaN(width) || isNaN(height)) { throw new Error("Parameter is not a number!"); } return width * height; } try { getRectArea(3, "A"); } catch (e) { console.error(e); // Error: Parameter is not a number! }
Built-in error types you will see often:
ErrorTypeErrorRangeErrorReferenceErrorSyntaxError(usually from the parser, notthrow)
2. try...catch
try { // code that might throw } catch (error) { // handle the error }
- Code inside
tryruns first. - If anything throws (including functions called from inside
try), execution jumps straight tocatch. - If nothing throws,
catchis skipped.
You can omit the error variable if you don’t need it (ES2019+):
function isValidJSON(text) { try { JSON.parse(text); return true; } catch { return false; } }
You can also destructure the error:
try { throw new TypeError("oops"); } catch ({ name, message }) { console.log(name); // "TypeError" console.log(message); // "oops" }
Classic example
function getMonthName(mo) { const months = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ]; const name = months[mo - 1]; if (!name) { throw new Error("Invalid month code"); } return name; } let monthName; try { monthName = getMonthName(13); } catch (e) { monthName = "unknown"; console.error(e.message); }
3. the finally block
finally always runs before control leaves the try/catch/finally construct — after a successful try, after a catch, or even if you return/throw/break/continue inside try or catch.
try { // risky work } catch (e) { // handle } finally { // cleanup — this always runs }
You can also use try...finally without a catch.
Resource cleanup (the most common use)
openMyFile(); try { writeMyFile(theData); // might throw } catch (e) { handleError(e); } finally { closeMyFile(); // always close, even on error }
Important nuance: return inside finally
If finally contains a return (or throw), it overrides any return/throw that happened in try or catch. Avoid control-flow statements in finally unless you really intend this behavior.
function test() { try { return "from try"; } finally { return "from finally"; // this wins } } console.log(test()); // "from finally"
4. putting it together: try...catch...finally
All three blocks together:
try { console.log("Opening connection"); throw new Error("Connection failed"); } catch (err) { console.error("Error:", err.message); } finally { console.log("Closing connection"); } // Output: // Opening connection // Error: Connection failed // Closing connection
5. custom errors
Create your own error classes by extending Error. This lets callers distinguish error types with instanceof.
class ValidationError extends Error { constructor(message) { super(message); this.name = "ValidationError"; } } function checkAge(age) { if (age < 18) { throw new ValidationError("User must be 18 or older"); } return "Access granted"; } try { checkAge(16); } catch (e) { if (e instanceof ValidationError) { console.log("Validation problem:", e.message); } else { throw e; // rethrow unexpected errors } }
Rethrowing is a best practice: catch only what you know how to handle; let everything else bubble up.
6. nested try / catch
You can nest them when different layers need different handling:
try { try { riskyInner(); } catch (inner) { console.log("Inner handled:", inner.message); throw inner; // or wrap and rethrow } } catch (outer) { console.log("Outer handled:", outer.message); }
7. asynchronous code
try...catch only catches synchronous throws and awaited rejections.
async function loadUser(id) { try { const res = await fetch(`/api/users/${id}`); if (!res.ok) { throw new Error(`Failed to fetch user ${id}`); } return await res.json(); } catch (err) { console.error(err); // handle or rethrow } finally { // hide spinner, release lock, etc. } }
For raw Promises (no await), use .catch() / .finally() on the promise chain instead.
Uncaught promise rejections and uncaught exceptions still go to the global handlers (window.onerror, unhandledrejection).
8. best practices
- Throw
Errorobjects (or subclasses), not raw strings/numbers. - Catch only errors you can actually recover from. Rethrow the rest.
- Use
finallyfor cleanup (close files, release locks, hide loaders, reset state). - Don’t use
try...catchfor normal control flow — it is for exceptional situations. - Don’t swallow errors silently (
catch {}with no logging). - Give errors clear, specific messages.
- Prefer
instanceofchecks over string matching onerror.name. - In modern JS you can also use
using/await usingdeclarations for automatic resource disposal (see MDN Resource management), which reduces nestedtry...finallyboilerplate.
9. common pitfalls
| Pitfall | What happens |
|---|---|
Forgetting await inside try |
The promise rejection is not caught by that try...catch. |
return / throw in finally |
Overrides the original return/throw. |
| Catching everything and ignoring it | Bugs become invisible. |
| Throwing non-Error values | Harder to debug (no stack, inconsistent shape). |
Using try...catch around every line |
Makes code noisy and can hide real problems. |
Quick reference
try { // might throw if (badInput) throw new TypeError("bad input"); } catch (error) { if (error instanceof TypeError) { // handle this type } else { throw error; // rethrow } } finally { // always runs (cleanup) }
That’s the core of JavaScript exception handling. Start with throw + try...catch for validation and expected failures, add finally whenever you acquire a resource that must be released, and keep catch blocks focused.