Blog Home » TODO: Error Handling in BackboneJS

TODO: Error Handling in BackboneJS

By Nick Pelton

Welcome to the next installment of the TODO Error Handling series from TrackJS. We’ve looked at the TODOMVC.com example applications and wiring them up for better error handling with TrackJS. In other posts, we’ve covered:

BackboneJS is an open-source JavaScript application framework, often used for single-page applications. In this integration, we’ll be using the BackboneJS TODO app from TODOMVC.com as our example application.

BackboneJS Error Handling

BackboneJS is a very light weight framework and doesn’t provide much in extra error handling. One example is the Backbone.sync() method, it offers .success() and .error() callbacks for handling AJAX errors, but in most other cases the exception will simply bubble up to the native error handler so you probably won’t get a stacktrace unless you wrap your code in try/catch blocks. So you have to lean on JavaScript’s native error handling.

In this example we run a function that throws an error we’ve wrapped it in a try/catch so the exception can be caught, then we can choose the appropriate steps to handle the error. Modern browsers will also pass a stack parameter as part of the error object providing a stack trace.


try {
  throw new Error("Something broke!");
} catch (exception){
  // Handle exceptions
  console.error(exception.message);
} finally {
  // This code will execute when the try and catch are done
  console.log("done!");
}

try is used to protect code that could cause an exception and the catch is only executed if an exception occurs. finally will run in either case, helping you cleanup anything. We can also use throw to generate our own errors when we know an error has occurred.

Obviously, we don’t want to fill up all of our code with try/catch/finally everywhere, but if we knew how the code would fail, we would have written if differently in the beginning. Stay tuned, we’ve got some tricks for TrackJS to wrap up everything later.

Integrating TrackJS

Extending the basic capabilities of BackboneJS with TrackJS allows you to track and trend how your application breaks. Basic integration with BackboneJS is as simple as copying the TrackJS snippet into your application. Simply signup for a TrackJS account and paste the script into your markup.

Basic Error Integration

TrackJS enhances BackboneJS error handling, greatly increasing the chance of getting a stack trace. Let’s create an error to see what kind of data TrackJS captures for us out of the box. Start by simply using the App, create a few TODOs, edit one, and delete one. Once you feel good about your list, open the browser console and enter console.error("Something broke!").

Open TrackJS and you’ll see the error was captured along with tons of user interactions and data. For user inputs, we provide the user action, element markup snapshot, and a value interpretation. We never send input data to TrackJS, we instead parse the HTML and regex the values, then filter out the value info before we collect it. This is a secure way to give you insight to the type of input without exposing private data.

Customized Error Integration

You already get great coverage with a basic installation of TrackJS, but in some cases you may fail to get a stack trace. This often happens when a method fails to pass an error object back to the native error handler. luckily TrackJS provides some handy API methods to quickly setup try-catch blocks without complicating your code. Try-catch all the things!


// Automatically wrap everything
if (!window.trackJs) return;

["View","Model","Collection","Router"].forEach(function(klass) {
  var Klass = Backbone[klass];
  Backbone[klass] = Klass.extend({
    constructor: function() {
      // NOTE: This allows you to set _trackJs = false for any individual object
      //       that you want excluded from tracking
      if (typeof this._trackJs === "undefined") {
        this._trackJs = true;
      }

      if (this._trackJs) {
        // Additional parameters are excluded from watching. Constructors and Comparators
        // have a lot of edge-cases that are difficult to wrap so we will ignore them.
        window.trackJs.watchAll(this, "model", "constructor", "comparator");
      }

      return Klass.prototype.constructor.apply(this, arguments);
    }
  });
}); 

You can see this example and more details in our documentation.

In this code sample we’ve wrapped up BackboneJS core objects (View, Model, Collection, Router) using the TrackJS API. This extends the backbone models using trackJs.watchAll(); which iterates over objects and returns each method with a try-catch block around it. There are a few cases where this can break methods, so depending on your application you can exclude specific methods to prevent incompatibilities. You can also wrap individual methods like so:


// Selectively wrap objects on instantiation.
var MyView = Backbone.View.extend({
  initialize: function () {
    if (window.trackJs) {
      window.trackJs.watchAll(this, "excludedFunction");
    }
  }
});

Now we’ll break our BackboneJS application by causing an error. Open up todo_controller.js and add an undefined(); function within the actions.removeTodo method.


// In app.js
createOnEnter: function (e) {
  if (e.which !== Common.ENTER_KEY || !this.$input.val().trim()) {
    return;
  }

  // Oops, we broke it
  undef();

  Todos.create(this.newAttributes());
  this.$input.val("");
},

Reload our app and try to add a new todo. Nothing happens (as planned) and an error is thrown and captured to TrackJS. Open TrackJS and navigate to the new error, you’ll see that we’ve captured the stack trace as well as some additional context.

Backbone Advanced Error

Application Specific Information

Getting an error message, stacktrace plus app telemetry adds so much more insight into your applications errors. With some simple TrackJS config options you can add application specific context for your own reference when reviewing application errors. You can easily add these parameters in the _trackJs config object on initialization.


TrackJS.install({
  version:    "VERSION_FROM_SERVER",
  sessionId:  "SESSIONID_FROM_SERVER",
  userId:     "USERID_FROM_SERVER",
  application:"APP_SLUG_FROM_TRACKJS",
  token:      "YOUR_TOKEN_FROM_TRACKJS"
});

If you cause the same undefined error you’ll see the additional data in the “Application Information” box. You can also filter errors by UserID directly from this box, or by navigating to the “Users” tab once you’ve logged UserIds. “Applications” adds the ability to segment all error data using a simple application slug in your config, simply add your app in the TrackJS Applications page and add the slug to your config.

Custom Logging

The Telemetry Timeline is super helpful for replicating errors and it can speak volumes when you add additional log info. For example, we can log applications events, initializations, timestamps, and more. This data will be captured in the timeline. We’ve added some console.log() calls during initializations and when specific methods fire–building your own black-box of events in case an error occurs. We’ve decorated the code with some logging statements to give a more thorough history of the TODOMVC behavior.

Backbone Custom Error

Custom Events

Want to track your own Telemetry events? At any time you want to capture the latest network, console, and user interactions simply call trackJs.track() method. In this case we simply want to see what was going on right before the user edits a todo. Simply add trackJs.track("custom event capture"); at the point you want to capture TrackJS history. This can be incredibly handy when trying to track down a UI or logic error that doesn’t actually cause an exception.


Another JavaScript framework protected by TrackJS. We hope you learned a bit about error handling in BackboneJS and how easy it is to get started with error handling. If you haven’t already, grab a free 14-day trial and let us help you start finding and fixing bugs in your BackboneJS applications!

Nick Pelton
Nick Pelton