When JavaScript hits an error it cannot recover from, it throws an error and stops running the current code. With try...catch you can handle the error and carry on.
try {
console.log("Before");
JSON.parse("this is not JSON"); // throws an error
console.log("Never printed");
} catch (error) {
console.log("Caught:", error.name); // → Caught: SyntaxError
}
console.log("The program continues");
The parts
try: the code that might throw. If it throws, the rest of thetryblock is skipped.catch (error): runs only if something threw.errordescribes the problem.finally: runs always, whether or not there was an error. It is for cleanup.
function readSetting(text) {
try {
return JSON.parse(text);
} catch (error) {
console.log("Could not read settings:", error.message.length > 0);
return {}; // a safe fallback
} finally {
console.log("done reading"); // runs even though we returned above
}
}
console.log(readSetting('{"theme":"dark"}')); // → { theme: dark }
console.log(readSetting("oops")); // → {}
The error object
| Property | Meaning |
|---|---|
error.name | the kind of error, for example TypeError |
error.message | a short description |
error.stack | where it happened (useful for debugging) |
try {
null.property;
} catch (error) {
console.log(error.name); // → TypeError
console.log(error.message.length > 0); // → true
}
Optional catch binding
If you do not need the error object, leave it out:
try {
JSON.parse("{bad");
} catch {
console.log("invalid JSON"); // → invalid JSON
}
finally for cleanup
<button id="save">Save</button>
<p id="out"></p>
<script>
const button = document.querySelector("#save");
button.addEventListener("click", () => {
button.disabled = true;
try {
throw new Error("Saving failed");
} catch (error) {
document.querySelector("#out").textContent = error.message;
} finally {
button.disabled = false; // always give the button back
}
});
</script>
What try…catch cannot catch
- Syntax errors in the same script: the code never runs at all.
- Errors inside callbacks that run later. A
tryaroundsetTimeout(...)does not catch what happens inside the timer. Put thetry...catchinside the callback. - Rejected promises unless you
awaitthem intry, or use.catch(): see async error handling.
try {
setTimeout(() => { throw new Error("late error"); }, 0); // error on purpose: not caught by the try below
} catch {
console.log("never runs");
}
Do not hide errors
An empty catch {} silently swallows problems and makes bugs invisible. At least log the error, or show a message.
Use it where you can recover
try...catch where you can do something useful: a fallback value, a message to the user, a retry. Do not wrap whole programs in it “just in case”.