Lightning Talk: JavaScript Error Handling
-
Upload
nick-burwell -
Category
Technology
-
view
591 -
download
0
Transcript of Lightning Talk: JavaScript Error Handling
JavaScript Error HandlingNick BurwellPrincipal UX EngineerInvoca, Inc.
Why are JavaScript errors so scary?
Why are JavaScript errors so prominent?
Why are JavaScript errors so often ignored?
A few thoughts...Dynamic language, weakly-typed
Intersection of JS and HTML/DOM
Browser differences
Often lack of test coverage
Assets missing / order dependencies
Spotty networks, load errors
Do your developers & QA notice errors locally?
How easy are they to debug once they occur?
Do you know about errors that happen in production?
So how do we do better?CC: https://www.flickr.com/photos/verpletterend/5393470920
Do your developers & QA notice errors locally?
Components should enforce their contractRaise errors when not met
Don't just silently failProvide useful context to debug
Example from DataTables
Example from React componentsReact = require('react');
var Button = React.createClass({ propTypes: { title: React.PropTypes.string.isRequired }, ...});
Basic Error Handlingfunction foo() { if (typeof title === "undefined") { throw new Error("title should be defined"); }}
try { foo();} catch (ex){ // handle error}
Error Hierarchy
Error
EvalError RangeError ReferenceError SyntaxError TypeError URIError
Documentation: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error
Define your own Errorfunction NotFoundError(message){ this.message = message;}
NotFoundError.prototype = new Error();
...
throw new NotFoundError("Could not find ID: foobar");
source
Surprising results!No stack, no error name
Define your own Errorfunction NotFoundError(message){ this.name = "NotFoundError"; this.message = message; this.stack = (new Error()).stack;}
NotFoundError.prototype = Object.create(Error.prototype);NotFoundError.prototype.constructor = NotFoundError;
...
throw new NotFoundError("Could not find ID: foobar");
< 8
Have an easy way to log errorsSimple interface
Adapt based on whether in dev or production
Show error prominently in dev!
Send to exception monitoring in production
Don't catch simply to log to consoleDon't simply log to console as the way to "handle" errors
try { // something that causes an error} catch (ex){ console.log("ERROR: " + ex.message + "\n" + ex.stack);}
Antipattern!
Expect the unexpectedvar status = this.model.get('status');switch (status) { case 'active': // do something here... break; case 'paused': // do something else here... break; case 'archived': // do different stuff here... break; default: Invoca.logError("No status handling for value: " + status, context);}
Catch and report ALL the errors!window.onerror = function( message, scriptUrl, lineNumber, characterNumber, error) {
// handle error! Notifier.log(message, error.stack);
// return true; prevents default browser handling}
Now supported by all modern browsers (even IE!) … except Safari
Before...You couldn't get a stack from window.onerror errors
Two common strategies to work around were:
Rely on onerror anyway
In production mode have a much harder problem debugging issues
Put try/catch's around all your code
Difficult to ensure around all event handlers, timers, ajax callbacks
If exception is caught in development, harder to use browser tools to debug
Middle ground: dynamically wrap with try/catch in production only
Now...Use window.onerror
Consider also using a library to wrap events / callbacks
In production, log errors to your error monitoring server
Invoca combines JS errors with our Rails / other ruby errors
Includes user / session / browser / URL data
3rd party solutions available
Bugsnag
Rollbar
In development, let unexpected errors bubble up / rely on browser tools
Minification & obfuscationEven a message & stack doesn't mean you can decipher uncaught errors
Solution: allow your sourcemap files to be accessible
developers can unobfuscate and make sense of errors
Ensure sourcemaps are enabled in your minifying / concatenating of assets
Rails asset pipeline doesn't provide out of box (fix with precompile task)
Node based options usually have config options for sourcemaps
A full development cycle strategyMake components easy to integrate with in development
Make things easy to debug in development & testing (when errors happen)
Report unexpected errors to a logging / monitoring system in production
Don't expose ugly exceptions to users in production
ResourcesPre-built logging & monitoring tools
Bugsnag: Product | JS logging repo
Rollbar: Product | JS logging repo
New Relic: Product
Log4JavaScript: Docs
Articles on JS errors
https://bugsnag.com/blog/js-stacktraces
https://www.nczonline.net/blog/2009/03/10/the-art-of-throwing-javascript-errors-part-2/
https://www.nczonline.net/blog/2009/04/28/javascript-error-handling-anti-pattern/
Thanks!