148

I'm looking to start making my JavaScript a bit more error proof, and I'm finding plenty of documentation on using try, catch, finally, and throw, but I'm not finding a ton of advice from experts on when and where to throw errors.

  • Should every piece of code be wrapped in a try/catch?
  • Is there more advice like this on at what point errors ought to be caught?
  • Are there disadvantages to raising errors instead of having code fail silently in production?
  • This has been touched on on SO as far as implementations, but have server-logging JS errors an effective strategy?
  • Anything else I ought to know, regarding trapping errors in my application?

I'm also completely game for hearing of books that have great chapters or in-depth explanations of error-handling. Eloquent JavaScript touches on the matter, but isn't very prescriptive or opinionated about the issue.

Thanks for any advice you can give!

Joshua Cody
  • 3,742
  • 5
  • 32
  • 34
  • It surely depends on how spectacularly you fail if something goes wrong and the volume of possible error messages. You do not want to fail because your error logging directory is full now do you? - Did you look here at all? http://stackoverflow.com/search?q=error+logging+javascript – mplungjan Jun 26 '11 at 14:36
  • @mplungjan - I did scan through the answers there, but not a lot seemed canonical, and searches for Javascript error handling/exception best practices turned up nothing, so I thought it could be helpful to try and solicit some condensed thoughts, both for my own understanding and future searchers. Perhaps this is a topic where prescribing best practices isn't as possible, but each situation is highly unique? – Joshua Cody Jun 26 '11 at 15:29
  • 1
    "Should every piece of code be wrapped in a try/catch?" Of course not. There's lots of code that you know will always work (assuming you test it, of course, but the point of try/catch is not to catch or gloss over coding errors). Only wrap code that might fail some of the time due to something outside its control, generally things like resource access, etc. Note: some things that can fail have built-in error handling, e.g., I would not bother coding Ajax from scratch when there are plenty of libraries that do it which handle cross-browser issues and let you specify an error handler function. – nnnnnn Jun 27 '11 at 01:32
  • 1
    This is a good question Josh, +1. Lot's of syntactic advice around, but like you say that's the easy part. It is touched on in this question's answer (http://stackoverflow.com/questions/2825427/what-are-the-standard-practices-for-throwing-javascript-exceptions) where it's explained that Exceptions are not as commonly used in JS and reasons are given. – whitneyland Dec 06 '11 at 20:35

5 Answers5

67

An immensely interesting set of slides on Enterprise JavaScript Error Handling can be found at https://web.archive.org/web/20140126104824/http://www.devhands.com/2008/10/javascript-error-handling-and-general-best-practices/

In short it summarizes:

  1. Assume your code will fail
  2. Log errors to the server
  3. You, not the browser, handle errors
  4. Identify where errors might occur
  5. Throw your own errors
  6. Distinguish fatal versus non-fatal errors
  7. Provide a debug mode

The slides go into much more detail and most probably will give you some direction.

EDIT:

The presentation mentioned above can be found here: https://www.slideshare.net/nzakas/enterprise-javascript-error-handling-presentation

Kos
  • 4,890
  • 9
  • 38
  • 42
cdmdotnet
  • 1,663
  • 3
  • 17
  • 22
30

Nicholas Zakas of Yahoo! fame did a talk on Enterprise Error Handling (slides) at Ajax Experience 2008, in which he proposed something like this:

function log(sev,msg) {
    var img = new Image();
    img.src = "log.php?sev=" +
        encodeURIComponent(sev) +
        "&msg=" + encodeURIComponent(msg);
}

// usage
log(1, "Something bad happened.")

// Auto-log uncaught JS errors
window.onerror = function(msg, url, line) {
    log(1, msg);
    return true;
}

A year later, Nicholas Zakas posted an update on his blog which included a clever pattern to inject error handling code automatically on your production environment (using aspect-oriented programming).

When you start logging window.error calls, you're going to notice two things:

  1. If your site is fairly complex, you're going to log a lot of errors
  2. You'll be seeing a bunch of useless "window.error in undefined:0" messages

Reducing the torrent of log entries is as simple as testing for severity and/or a random number before logging to the server:

function log(sev,msg) {
    if (Math.random() > 0.1) return; // only log some errors

    var img = new Image();
    img.src = "log.php?sev=" +
        encodeURIComponent(sev) +
        "&msg=" + encodeURIComponent(msg);
}

Handling the useless window.error in undefined:0 errors depends on your site architecture, but can try identifying all Ajax calls and throwing an exception when something fails (possibly returning a stack trace using stacktrace.js).

Kos
  • 4,890
  • 9
  • 38
  • 42
Jens Roland
  • 27,450
  • 14
  • 82
  • 104
  • 76
    I know this is an old question, but suggesting to randomly ignore some errors is one of the worst ideas I've ever heard. – jbabey Feb 01 '13 at 14:00
  • 34
    @jbabey: For a small site you are right, but if you are running a large site with 100,000s or millions of users, you really don't need to flood your servers (or the internet) with redundant logging requests. On a large enough system, every real error is going to occur tens of thousands of times a day, so this form of limiting works just fine. The idea is actually implemented at Facebook. – Jens Roland Feb 02 '13 at 08:30
  • 1
    Logging errors while in debugging mode is likely just as important as limiting production error reports, so one may note that a solution is needed for managing that value limiting the logging threshold. – frattaro Oct 02 '15 at 03:52
  • @JensRoland Have you any source for that claim about Facebook using this method? I find that really troubling that any company at production would randomly ignore errors, and not just create an accumulative "count" for the repeating errors, which could incrementally be sent to the server (i.e, log after every 10 errors, same number of requests sent logging errors as ignoring 9/10 of them, but you keep all the error information). – Nick Bull Apr 25 '17 at 10:59
  • 2
    @NickBull I reverse engineered a bunch of Facebooks JavaScript modules back in 2011-2012; that's where I found it. – Jens Roland Apr 26 '17 at 15:31
  • 1
    @NickBull just checked my old files, still had these. I found this trick in the Facebook bootloader module: `if (global.logJSError) if (Math.random() < .01) logJSError('bootloader', {` (admittedly that code doesn't throttle all errors, only a specific class of timeout errors) – Jens Roland Apr 26 '17 at 15:43
  • 1
    @JensRoland +1, awesome finds! Crazy to see how shoestring code is even for the biggest companies can be in production sometimes. – Nick Bull Apr 27 '17 at 20:19
  • 1
    @NickBull based on what I've seen I'd say that Facebooks front end code is anything but 'shoestring'. I believe throttling high-frequency errors is a solid move when your application traffic is above a certain level. Logging 1% of errors randomly means you WILL see all significant errors, and the throttling only means you notice them a little later -- with the most critical/frequent ones being delayed the least, just as you'd want. I'll leave the probability proof as an exercise to the reader. – Jens Roland Apr 28 '17 at 19:59
  • @JensRoland Thank you! – Nick Bull Apr 29 '17 at 14:06
  • A "better"? solution would be to check if the current error is the same as the previous error, if false print the error, if true, then just increase a local error_count variable and update the previous error (works poorly for alternating errors). If you have many alternating errors, make a list of reasonable length, check whole list for same error, if not present print error, else increase local error counter for that error. Example: "Error: bla error bla, has appeared 598 times" – Sebastian Norr Mar 13 '19 at 16:46
  • @SebastianNorr Alternating errors is not the only issue; when you have thousands (or for Facebook, millions) of concurrent users, even errors which only happen a few times for any individual user could still generate thousands of identical error logs on the server, and deduping on the client side can't help that. Also, you generally want to keep error logging code simple to ensure that the errors are logged quickly and reliably. – Jens Roland Mar 13 '19 at 18:18
8

IHMO, you should use error handling in javascript like you do in several other languages (AFAIK: Python, Java).

For better readability (and probably better performance, even though I am not sure it has a really big impact), you should use the try / catch block mostly on the following cases :

  • The part of the code you want to wrap is a key part of the whole algorithm. If it fails, it could :

    • create errors on the next part of the codes (e.g. because a var is missing...)
    • make the page not look what expected (impact on content or css)
    • make the results appear strange to the user (impact on the code behavior)
  • You know that the code you are writing is not compatible with every browser

  • You planned that the code may fail (because there is no other way to check that it should work by if...then... blocks)
  • And also when you want to debug without bothering the final user

Eventually, javascript experts may have other elements to give.

my 2 cents to the box,

Regards,

Max

kon psych
  • 626
  • 1
  • 11
  • 26
JMax
  • 26,109
  • 12
  • 69
  • 88
  • 2
    "The part of the code you want to wrap is a key part of the whole algorithm" - might depend on how you want to handle the failure. If you know there is no way to continue with the algorithm upon failure it might be better to wrap the whole thing in a try/catch because if your try/catch is (e.g.) buried inside nested loops it will be more of a performance hit. On the other hand if you can take some action on exception and continue with the algorithm then you will need a more fine-grained try/catch setup. – nnnnnn Jun 27 '11 at 01:52
5

In addition to the other answers: one important thing is to use context data available in JavaScript error objects and in the window.onerror function parameters.

Things like the stacktrace (errorObject.stack), the filename, the line number and the column number. Note that each browser has some differences...so do your best effort to get nice errors.

There can even be problems with the console object itself. I use a custom window.onerror function inspired by this one and a special function to trace any given standard error object inspired by this code.

Another good point is to include the version of your web application somewhere close to the stacktrace (for quick and safe copy and pasting). You may also show errors more aggressively (alert...) in development mode as developers will not constantly monitor the browser console and may not see some of the problems.

Also use avoid using throw 'My message', use throw new Error('My message'), you can even have custom errors, read this article.

Always add some context to the errors (the version, the id of the object, some custom message, ...) and also make sure you make a distinction between external errors (some external data or circumstance made your system fail) and internal errors/assertions (your own system messed up), read about 'Design by contract'.

Here is a guide.

Also think about using general error handling like interceptors your libs and frameworks:

Christophe Roussy
  • 16,299
  • 4
  • 85
  • 85
0

I created script for that. It blocking all console commands except items mentioned in allow list, or block everything in blocklist. Works good even with colored console logs.

https://github.com/iiic/consoleFilter.js

iiic
  • 1,366
  • 2
  • 15
  • 23