📖 Deeper dive reading: MDN try...catch
JavaScript supports exception handling using the try catch and throw syntax. An exception can be triggered whenever your code generates an exception using the throw keyword, or whenever an exception is generated by the JavaScript runtime, for example, when an undefined variable is used.
To catch a thrown exception, you wrap a code block with the try keyword, and follow the try block with a catch block. If within the try block, including any functions that block calls, an exception is thrown, then all of the code after the throw is ignored, the call stack is unwound, and the catch block is called.
In addition to a catch block, you can specify a finally block that is always called whenever the try block is exited regardless if an exception was ever thrown.
The basic syntax looks like the following.
try {
// normal execution code
} catch (err) {
// exception handling code
} finally {
// always called code
}For example:
function connectDatabase() {
throw new Error('connection error');
}
try {
connectDatabase();
console.log('never executed');
} catch (err) {
console.log(err);
} finally {
console.log('always executed');
}
// OUTPUT: Error: connection error
// always executedImportant
When first using exception handling it is tempting to use it as way to handle normal flows of execution. For example, throwing a file not found exception when it is common for users to request nonexistent files. Throwing exceptions should only happen when something truly exceptional occurs. For example, a file not found exception when the file is required for your code to run, such as a required configuration file. Your code will be easier to debug, and your logs more meaningful if you restrict exceptions to truly exceptional situations.
The fallback pattern is commonly implemented using exception handling. To implement the fallback pattern you put the normal feature path in a try block and then provide a fallback implementation in the catch block. For example, normally you would get the high scores for a game by making a network request, but if the network is not available then a locally cached version of the last available scores is used. By providing a fallback, you can always return something, even if the desired feature is temporarily unavailable.
function getScores() {
try {
const scores = scoringService.getScores();
// store the scores so that we can use them later if the network is not available
window.localStorage.setItem('scores', scores);
return scores;
} catch {
return window.localStorage.getItem('scores');
}
}