I love conditional breakpoints. Really! They’re my favorite debugging tool.
When I got started in web development, “debugging” for me meant creating a
<pre id='log'></pre> and appending strings to its contents to act as a log. But once Firebug rolled around—and then when browsers started baking in their own dev tools—it was like upgrading from a skateboard to a private jet. Breakpoints, watches, call stacks, profilers, network activity monitors—they’re all useful, and I wouldn’t want to lose any of them.
But conditional breakpoints are my favorite, and it’s not even close. Here’s how I use them:
The obvious case is the one that’s documented everywhere: creating a breakpoint that only pauses execution when a particular expression evaluates to
Using conditional breakpoints this way is nice when I’m trying to track down some weird behavior in a section of code that runs often, but whose behavior is broken only in the presence of specific combinations of data. A normal breakpoint would just pause execution every time and debugging would be tedious, but a conditional breakpoint allows you to pause only when the right data are present, so you can stop and look around. Nice.
But that’s the mundane usage. Honestly, it’s probably the least common way I use them. You see, conditional breakpoints are a scalpel. They’re a monkey patcher’s dream.
Have you ever been in a situation where you wanted console access to a variable defined locally in a function, but from an execution context outside the function? This happens to me all the time; I want to let my app load and run until an idle state, and then be able to inspect, say, properties or methods on some object locked away in a closure. Conditional breakpoints to the rescue!
The main trick here is to use the lowly comma operator to make sure that the assignment doesn’t evaluate as truthy, because that would cause the breakpoint to pause execution. Instead, the breakpoint expression evaluates to
false and the app flies right through it and runs until idle, and then you can inspect the value in the console to your heart’s content just by typing its name.
Note: I make a habit of doing
window.varName rather than just
varName so I don’t accidentally modify a variable that exists in an outer scope relative to the location of the breakpoint.
Protip: in an ES2015+ enabled browser, export a series of variables quickly with shorthand property names:
window.dealyBob = , false
Using the comma operator this way is the key to making conditional breakpoints sing.
My most common use case for conditional breakpoints is logging. I know it’s common among professional developers to poke fun at
console.log-driven development, but being able to instrument your code without rebuilding or even reloading, watch everything run in real time, and get detailed diagnostic output is fantastic.
What’s wonderful about this is, the Dev Tools will save the breakpoints’ associations with the file(s) in question (at least in Chrome, where I tend to work most often these days), so they’re still there the next time I load the app in a different session, without me actually having to save any changes to my app code! This gives me a kind of runtime Aspect-oriented logging system that lives purely in the browser. How’s that for separation of concerns?
Say you have a bug where the repro is to have a particular combination of data loaded, and to get to that state you have a number of tedious steps to follow first. Not anymore! As a keen reader, I’m sure you noticed earlier that if you can modify properties on
window to create new global variables in a conditional breakpoint expression, there’s nothing stopping you from modifying anything else.
So go ahead and paste a bunch of JSON into a conditional breakpoint and assign it to whatever variables you need. Boom! Say goodbye to the tedious repro.
Protip: the comma operator allows you to chain more than just two statements together, so if you have a whole set of assignments to make, go right ahead and say:
(var1 = x; var2 = y; var3 = z), console.log('overriding with', x, y, z), false
Related Protip: don’t forget that you can set values on any global object from the console; if you have particularly large objects to use as overrides, or if you want to change the data a conditional breakpoint will use without having to modify the actual breakpoint, get thee to the console and say
window.bigOverrideObject = , and then in the conditional breakpoint expression,
var1 = window.bigOverrideObject, false
Insert a conditional breakpoint anywhere you like, and run whatever you want! There are a few limitations—for example, you can’t
return from the current function directly in the breakpoint expression—but for the most part, you can do whatever transformations or computations your app needs.
This is where the monkey patching aspect comes in: you can combine all of these techniques and use conditional breakpoints to overwrite entire functions, even when they’re inside a closure. Check it:
Pretty sneaky, sis! (warning: ’80s kid reference)
Protip: your dev tools obviously aren’t modifying the deployed app code, so this makes for a great way to try things in your production system without doing a whole build/deploy cycle. Be careful not to tweak things in such a way that they end up wrecking your production data, however!
I love conditional breakpoints. And now I hope you do too!
PS: special thanks to my pal and fellow conditional breakpoint enthusiast Brian Sinclair for reviewing this article, and for the conversation that inspired it. His love for conditional breakpoints is truly unconditional.
About Revin Guillen