lightning talk: javascript error handling

Post on 13-Apr-2017

598 Views

Category:

Technology

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

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!

top related