- this whole server is borked
- this user session is broken
- whatever action i just tried to complete did not work
- an error will happen if we continue, so let’s not
- who cares
- call me right now
- e-mail me after it’s happened a few times
- log it, so i can dig in later if i hear something
- tell the user about the problem, not me
- who cares
- Works (silently handle the error)
- Stop me from causing an error
- Apologize, because a task couldn’t complete and help me understand why
- Apologize, because a task couldn’t complete
- Apologize
- Broken
var express = require("express");
var app = express();
app.get("/", function(req, res) {
res.send(undefined, "hello world");
});
app.listen(3000);
- The Callback Pattern
- Custom Error Objects
fs.readFile("file.txt", function(err, data) {
if (err) {
// do something nice
}
});
function MountainError(message) {
Error.captureStackTrace(this);
this.message = message;
this.name = "MountainError";
}
MountainError.prototype = Object.create(Error.prototype);
// var x = new MountainError("Too cold exception.");
// x instanceof MountainError; // true
// x instanceof Error; // true
// typeof x.stack; // String
// x.name; // "MountainError"
// x.message; "Too cold exception"
http://www.devthought.com/2011/12/22/a-string-is-not-an-error/ https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error
- incomplete data structures
- validation errors
- JSON parsing
function Person(options) {
this.name = options.name;
}
var j = new Person({name: “Jamund”});
At some point we start to expect that the name property exists on persons, so we build off it
function sendPersonToTimeOut(person) {
console.log(person.name + ‘ gets sent to timeout’);
}
Let's make a Todd:
var todd = new Person({
name: ‘Todd’,
family: {
wife: ‘Shelly’,
kids: [’Billy’, ‘Bob’]
}
});
And so we then create a new function.
function sendKidsMoney(person) {
person.family.kids.forEach(sendMoneyToKid);
};
This works when family exists and kids is an Array, but it doesn’t work in the rest of the cases.
Moral of story. Basically, just pretend you have types and prefill things as much as possible.
function Person(options) {
this.name = options.name;
this.family = options.family;
this.family.kids = this.family.kids || [];
}
http://underscorejs.org/#defaults can make this easier.
- This will give v8 a better chance at optimizing your code http://www.html5rocks.com/en/tutorials/speed/v8/
Basically an easy way to do this is to have a validate() function that returns true or false. These are usually errors that we can do something about given enough information.
var user = new Person({name: "Jamund"});
if (validate(user)) {
saveUser(user);
} else {
// but what information is missing?
tryToCollectionMoreInformation();
}
We can be more robust if we provide a way to see the errors.
var errors = getValidationErrors(user);
if (!errors.length) {
saveUser(user);
} else {
tryToCollectMoreInformation(errors);
}
You just need an array of issues:
function getValidationErrors() {
return [{
field: "name",
errorType: "required"
}];
}
Some people already figured out a way to handle all of this stuff: https://www.npmjs.org/package/jsonschema
Similar to the issue with incomplete data structures, errors while parsing JSON can be pretty detrimental to your application. Consider the following examples.
// @returns {User}
function parseUser(json) {
var user = JSON.parse(badJSON);
return user;
}
var badJSON = "{'name':'Jamund'}";
var user = parseUser(badJSON);
Here's a safer example:
// @returns {User}|{null}
function parseUser(json) {
try {
return JSON.parse(badJSON);
} catch(e) {
return null;
}
}
var badJSON = "{'name':'Jamund'}";
var user = parseUser(badJSON);
if (user === null) {
// precise checking for null is a good way to tell that this is broken
}
try/catch- Express Default Error Handler
- Uncaught Exception Handling
- Have a standard API for error handling
- localized error message
- field-specific error messages (for form validation)
- Deal with catastrphic failure in a sane way (timeouts, etc.)
- Send any client-side errors back to the server
- Don't
throwunless you want your server to blow up Errorobjects everywhere, use customErrorobjects if needed- Provide a consistent error API for your AJAX calls
- Use static analysis to enforce the pattern eslint/eslint#633