There are two different ways to handle errors in JavaScript. You can treat them as variables, or throw them. Both have their use cases, and you can convert back and forth between them using design patterns. Lets take a look at how each behave.
If you are coming from another language, you are probably already familiar with try catch. Here is a basic example:
function trycatch() {
var exception = {}
exception.message = "We borked!"
exception.code = 42
throw exception
}
try {
trycatch()
console.log("Success!")
} catch(e) {
console.log("Error number: "+e.code)
console.log("Error Message: "+e.message)
} finally {
console.log("All code has been run")
}
When you throw
an excpetion, the execution of the current function immediately stops. Execution is handed back up the stack to the first enclosing catch
block. After all execution in a try-catch block has run, the finally block will run. In this example, the output would be:
Error number: 42
Error Message: We Borked!
All code has been run
Note how console.log("Success!")
was not run.
There are two disadvantages to the try-catch clause.
- Uncaught exceptions will crash your program
- They do not translate to asyncronous code.
An example of when number 2 in our list will cause problems for you:
var fs = require('fs')
try {
fs.readFile('example.text',function(e,data) {
if(e) throw e
else console.log(data)
})
} catch(e) {
console.log("CAUGHT!")
}
Here, the opening of the file happens off the main thread. This is a huge problem for our callback as when it is executed, it is no longer in the same context as our try-catch. This means, when we throw e
, we are going to crash the program since nothing will be there to catch e
.
The solution to these two problems come in the form of Error variables, which we hinted at when we excepted an error as a paramater for our callback in the above example.
To learn more about try-catch and throw, take a look at the following two MDN articles:
Error variables are great for asyncronous code, and will not crash your program. Lets take a quick look at an example.
function error(cb) {
cb(new Error("We borked!")
}
error(function(e) {
if(e) return console.log(e.stack)
})
To learn more about errors, take a look at the following MDN article:
function throwit() {
throw "failed!"
}
function convert(cb) {
try {
throw()
} catch(e)
if(e) return cb(e)
}
return cb(null)
}
convert(function(e) {
console.log(e)
})
function callback(cb) {
return cb(Error("Failed!"))
}
function convert() {
callback(function(e) {
if(e) throw e
})
}
try {
convert()
} catch(e) {
console.log(e)
}
The second method is bad practice, as it can lead to your code failing in async execution.