This reading has some information and links to videos showing how to use the Chrome Debugger. Other debuggers work very similarly.

Concepts

The debugger does a few things for us. It allows us to

  • look at the values of local variables and function arguments
  • step line-by-line through the code
  • follow a function call into the called function, stepping through that line-by-line
  • skip function calls where we aren't interested in the function being called, while continuing to step through the code
  • see the sequence of function calls that got us to a particular place (the call stack)
  • execute code in a run-time context with the current local variables and arguments

If we have a lot of code (like with coffeerun), we usually don't want to step through all of it, starting at the beginning. Besides, with event-handling code, there often isn't a single beginning: any event handler could be a "beginning".

So, to tell the debugger that we want to stop at a particular line, we set a breakpoint at that line. Then we run our code as usual. When the browser gets to the breakpoint, it will pause the execution there. We can then:

  • look at values
  • start stepping
  • continue to the "next" breakpoint

We can set as many breakpoints as we want.

Enough preamble. Let's dive in and see a few examples, before we get to the example from Chapter 8

Ordinary Code

Try using the debugger on this example Here's the code that we'll be stepping through:

function foo(a,b) {
    let x = a+b;
    let y = a-b;
    return bar(x,y);
}

function bar(c,d) {
    let m = Math.sqrt(c);
    let n = Math.pow(d,3);
    return baz(m,n);
}

function baz(e,f) {
    let p = e+f;
    let q = e-f;
    return p*q;
}

function start() {
    console.log(foo(1,3));
}

I'll set a breakpoint at the "deepest" part of this code, and we can examine all the values up and down the stack.

Then I'll clear that breakpoint and set another at the beginning of the code, and demonstrate stepping through the code.

There is a video showing this on the videos page.

OOP Code

Object-oriented code isn't really much different, except that when we examine values, we can also examine values in the object, via the local "variable" this.

I'll use the debugger on this OOP example Here's the code that we'll be stepping through:

// this is our OOP bank account code 

class Account {
    constructor (init) {
        this.balance = init;
    }
    deposit (amount) {
        this.balance += amount;
    }
    withdrawal (amount) {
        if( this.balance >= amount ) {
            this.balance -= amount;
        } else {
            throw new Error("Insufficient funds");
        }
    }
}
var harry = new Account(1000);
var ron = new Account(2);
var hermione = new Account(200);

I'll set a breakpoint in one of the methods and invoke the method.

This is shown in the video mentioned above on the videos page.

Chapter 8

We can replicate the bug with the function bugSetup that I implemented for us, to avoid a bit of typing. We'll look at the definition first:

function bugSetup() {
    var truck = new App.Truck('bug',new App.DataStore());
    truck.createOrder({ emailAddress: 'm@bond.com',
                        coffee: 'earl grey'});
    truck.createOrder({ emailAddress: 'dr@no.com',
                        coffee: 'decaf'});
    truck.createOrder({ emailAddress: 'me@goldfinger.com',
                        coffee: 'double mocha'});
    return truck;
}

This code just creates a truck and creates some orders so that there is something to print.

Using the Chrome Debugger

To trigger the bug, visit one of these. Both open in a new tab.

In both, I've put the bugSetup code so that you can easily re-create the bug.

Then, we will try the following method invocations:

var b = bugSetup();
b.printOrders_buggy();
b.printOrders_closure();
b.printOrders_bind();
b.printOrders();

There's a video of using the Chrome debugger on our videos page.

Debugging Steps:

  1. Set a breakpoint at the line of the error
  2. show that esc opens/closes the drawer
  3. run myTruck.printOrders_buggy() again
  4. try pieces of the code, like id, this.db.get(id) and so forth in the console
  5. click up/down the call stack and try them again
  6. resume execution
  7. remove the breakpoint
  8. re-run the code to make sure the breakpoints are gone

Chrome seems to remember the breakpoints forever. I've had Chrome jump into the debugger when I'd set the breakpoint the previous semester. It's pretty easy to remove the breakpoints and resume the code, but it can be confusing to end up in the debugger when you didn't expect to.