Errors and try...catch
A program cannot always do what it is asked to: data arrives in the wrong format, a server does not respond, a required value is missing. When an error occurs, execution stops, and nothing written after that point runs. The try...catch construct lets you catch the error and carry on.
try and catch
Code that may fail goes into a try block. If an error happens, execution jumps straight to the catch block:
try {
JSON.parse('this is not JSON');
} catch (error) {
console.log('Could not parse the data'); // Could not parse the data
}JSON.parse() could not read the string and threw an error. Without try...catch the program would have stopped there. If there is no error, the catch block is simply skipped.
The error object
The parentheses after catch name a variable — it receives an object describing the error. Its name property holds the kind of error, and message the text:
try {
undefinedFunction();
} catch (error) {
console.log(error.name); // ReferenceError
console.log(error.message); // undefinedFunction is not defined
}Built-in error types
The error name tells you what went wrong. These are the most common ones:
| Type | When it happens |
|---|---|
ReferenceError | using a variable that was never declared |
TypeError | an action does not suit the value: calling a non-function, a property of undefined |
SyntaxError | code or JSON is written incorrectly |
RangeError | a number outside the allowed range |
try {
const user = undefined;
user.name;
} catch (error) {
console.log(error.name); // TypeError
}throw
The throw statement raises an error yourself. This is how a function reports that it cannot do its job. An error is created with new Error('text'):
function divide(a, b) {
if (b === 0) {
throw new Error('Cannot divide by zero');
}
return a / b;
}
try {
console.log(divide(10, 2)); // 5
console.log(divide(1, 0));
} catch (error) {
console.log(error.message); // Cannot divide by zero
}The first call worked, the second threw an error, and control went to catch — the second console.log never ran.
finally
The finally block always runs — both after a successful try and after catch. It is where you finish what you started: hide a loading indicator, close a file or a connection:
try {
console.log('Loading data');
throw new Error('Network failure');
} catch (error) {
console.log(error.message);
} finally {
console.log('Loading finished');
}
// Loading data
// Network failure
// Loading finishedCommon mistake
An empty catch block "swallows" the error: the program goes on with bad data, and finding the cause later is very hard.
try {
JSON.parse('{ broken }');
} catch (error) {
// empty: nobody will ever know about the error
}Catch only the errors you know how to handle. If you cannot handle one, at least report it with console.error(error).