DEV Community

Askara Novaru
Askara Novaru

Posted on

Debugging JS in the browser with breakOn

TLDR: See breakOn

The Problem

Last week, I came across a strange bug where an object's property was randomly changing in-between network calls. This particular object was being referenced in multiple places and I was having a hard time figuring out where exactly the change was happening. After spending some time debugging with debugger statements and chrome's devTools, I realized what I basically needed was to see a log of the objects modifications.

Option #1: Object.Observe

JS had a useful utility function Object.observe(obj, handler) method which track all actions on an object. So for this case I could just do a,

 Object.observe(obj, ...console.log);

and it would print out all the information for obj's props

Unfortunately this method has been deprecated and couldn't be enabled (easily) in chrome or any other modern browsers that I've tested.

Option #2: ES6 Proxy

The new Proxy in ES6 in recommended as the alternative to the old Object.observe, although they aren't functionally equivalent. Using proxy classes we can create a observer like so,

const observe = objToObserve => {
  const handler = {
    get: (obj, prop) => {
      console.log(`GET ${prop} = ${obj[prop]}`);
      return obj[prop];
    },
    set: (obj, prop, value) => {
      console.log(`SET ${prop} = ${value}`);
      obj[prop] = value;
      return true;
    }
  };
  return new Proxy(objToObserve, handler);
};

and now we can do

let me = { name: "John" };
me = observe(me);

me.name = "Jake";           // Console output: SET name = Jake
me.age = 12;                // Console output: SET age = 12

if (me.age > 10) {          // Console output: GET age = 12
  console.log("You're old enough to ride a bike!");
}

The problem here is that observe creates a new object, so we need to modify the original object reference wherever we want to track the changes. Which isn't much of a problem, but having to do that means that we need to be aware of where the reference is being initialized and modify it appropriately. This can also lead to problems if you're using const to initialize your variables. So although it would work, I was still not satisfied with this solution.

Option #3: breakOn

Enter breakOn.
I came across breakOn through stackoverflow and it's pretty much exactly what I need. breakOn is a single-file library that has a single method, breakOn. breakOn can set a breakpoint whenever a property changes ( or is accessed! ).
Here's how you use it,

const me = {name: 'John'}; // We can use const

breakOn(me, 'name');

person.me = "Jake"; // Breakpoint is triggered 

Now you can use add this as a snippet on chrome, and you can use it from chrome's devTool console on any site!

Unfortunately what I needed was logs, not really a breakpoint but the good news is that the function can easily be modified to do a console log (or any other action) instead of a break, which I ended up doing.

breakOn was exactly what I was looking for and although the code is a bit old now (2013'ish), and there are a lot of things that wouldn't be done the way it's done if it was written now, it served my use-case well and hopefully it'll come in handy for you too!

Top comments (0)