You're Doing Interfaces Wrong
Interfaces are everywhere, but still we have tight coupling, and inflexibility. Dependency inversion is the answer.
If you're using try/catch in JavaScript you're doing something WRONG. Here's why.
Check out my previous post about when it is and is not a good idea to use try/catch if you haven't read it already.
In this article I specify acceptable uses for try/catch in JavaScript. There aren't very many. In fact, I could only think of one reason applying to Node.js, even then, it's optional. So, let's start with the abundance of reasons NOT to use try/catch, starting with the biggest no-no:
Here is a bad vanilla JavaScript implementation of a network request with try/catch:
var xhttp = new XMLHttpRequest();
try{
xhttp.onreadystatechange = function() {
if (this.readyState === 4 && this.status === 200) {
showResponse(xhttp.responseText);
}
};
xhttp.open("GET", "filename", true);
xhttp.send();
}
catch {
showErrorMessage();
}
In the event of network error, the catch block will not trigger. The reason is as follows:
Reinterpreting the code as a timeline of events makes the problem a little more obvious:
At the end of this timeline the response was not shown... but neither was the error message. As far as the user knows, the request is still loading.
So how to handle network errors? The below is some vanilla JavaScript that handles server error responses correctly. It uses simple if statements on the readstatechange event, looking at properties exposed by the request object, and has an early abort to prevent downloading the whole response if we already know it's an error.
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if(this.readyState > 1 && this.readyState < 4){
if(this.status < 200 || this.status >== 300){
xhttp.abort();
}
}
else if (this.readyState === 4){ //when DONE
if (this.status >== 200 && this.status <300) { //success response
showResponse(xhttp.responseText);
}
else{
showErrorMessage();
}
}
};
xhttp.open("GET", "filename", true);
xhttp.timeout = 60*1000; //60 seconds
xhttp.ontimeout = showErrorMessage;
xhttp.send();
You may be wondering in the above example why we are bothering to check the status for readyState 4, seeing as we already checked the status for the earlier states and aborted if there was an error response.
The reason is that after the abort, the onreadystatechange callback will occur once more with a readyState of 4, so without checking, errors would produce the success response.
The native version of network error handling is messy and easy to get wrong. Many libraries offer easier alternatives that handle the logic. Nonetheless, try/catch is equally useless in this situation because the network request is still asynchronous. Here's an example of bad code that doesn't capture errors with a promise based scheme, such as that offered by Angular.
try{
httpclient.get("filename").subscribe(
function(response) {
showResponse(response.message);
}
);
}
catch {
showErrorMessage();
}
Now the correct version:
httpclient.get("filename").subscribe(
function(response) { //success callback
showResponse(response.message);
},
showErrorMessage //error callback
);
There are more reasons why try/catch shouldn't be used in client-side JavaScript.