Lesson Description

The "Source Debugger" Lesson is part of the full, Getting Started with JavaScript, v3 course featured in this preview video. Here's what you'd learn in this lesson:

Kyle introduces the sources tab, explaining how it allows students to step through their code line by line for detailed debugging. He demonstrates adding breakpoints using both the debugger text and the debugger tool, showing how to manage and remove them. Kyle then discusses the importance of managing breakpoints and explains the options for handling errors within the code using checkboxes for uncaught and caught exceptions.

Preview

Transcript from the "Source Debugger" Lesson

[00:00:00]
>> WebDevSimplified: So the next thing I want to talk about is going to be the sources tab, and this is really where you get into some much more complicated debugging because we've talked about how you can use console.log for certain debugging, but eventually you're going to get to the point where console.log just doesn't cut it. You're going to need way too many logs and it gets too confusing. This is where the debugger comes in because it allows you to step through your code line by line and see exactly what's going on at every single point inside of your code.

[00:00:21]
So let's go ahead and actually open up that sources tab and see what's going on. We're going to make this much larger because this is a rather large tab. You'll notice on the left-hand side, this tells us all the different files we currently have downloaded, so you can see we have a CSS file, we have a JavaScript file, and we have our HTML file being downloaded. Generally you're probably going to be messing with the JavaScript files though.

[00:00:40]
Then in the middle we have all of the code for that entire file showing up right on our page. This is the exact code that's being downloaded. Then on the right-hand side, we have a lot of different information about how we can interact with this when we start doing our debugging. Right now, this just shows us a static version of our code, but when we want to debug our code, we can actually see what's happening line by line.

[00:01:00]
So in order to debug your code, you need to add a breakpoint to your code. That's essentially a place in your code where you tell JavaScript, "Hey, stop right here and pause so I can see what's going on." There's two ways to add breakpoints. The first is if you're in your debugger, you can just click over here and if we click, it's going to add a breakpoint right there. So that means as soon as we get to that point in our code, it's going to stop.

[00:01:20]
So let's put one on line 2 right here, and then what I'm going to do is I'm just going to refresh my code by saving my file. That's going to refresh my page and you can see immediately over here it's now showing us, essentially we're stopped right here in our code. You can see it says we are currently paused, and it's telling me a bunch of information on the right-hand side of my screen for what's going on inside my code.

[00:01:40]
So for example, I can hover over different variables to see the exact value in them, and over here I have access to everything. For example, I have access to the scope of all the different variables in my file. I have access to my call stack. I have access to every single thing that's going on inside my application, and I can even control what I do. For example, if I click resume, that's just going to continue my code until I get to the next particular breakpoint.

[00:02:00]
Now the other way that you can add breakpoints in your code, which is a way that I find generally a little bit easier to work with, is you can just add in the text debugger. This essentially tells JavaScript when you get to this line where it says debugger, completely stop, and now you can see it got to that particular line and it completely stopped executing my code right where it got to debugger, and I can again continue on with my code if I want to.

[00:02:22]
Now to manage the breakpoints inside of our code, we go back into this section, we make it a little bit larger. You can see this section where it says breakpoints. Anytime I add a breakpoint, it shows up over here. I can toggle them on or off. I can remove them from here and manage all those different breakpoints from there. You'll also notice two different checkboxes: the pause on uncaught exceptions and pause on caught exceptions.

[00:02:42]
These handle how you want to handle errors inside of your code. So if I have an error inside my code, like a runtime error, the thing that I said is kind of hard to debug sometimes, and I don't know that that's happening, I can check this box right here for pause on uncaught exception. So anytime I have an error in my code that I didn't specifically handle, it'll pause me inside the debugger exactly where that error occurred.

[00:03:02]
So let's show you a quick example of what that looks like. I'm going to come in here, I'm going to kind of say const user equals Kyle. And then we'll just do a quick console.log of user, but I'm going to spell user wrong. We'll put two R's at the end of it. So now when I save my code, you can see my debugger over here completely stopped on the exact line where I had my error. It tells me what my error is, so I can look at my code and say, "OK, now I can figure out what this error is." Now this is a simple one to figure out, but if you have a more complicated error, this is a great way to figure out why that error is occurring, which is why I recommend leaving this checkbox checked whenever you're working with your code in the editor.

[00:03:40]
Now the second checkbox for pause on caught exceptions, I would recommend leaving unchecked. This essentially makes it so that the editor here pauses whenever you reach an error that you actually properly handle. There's certain ways in JavaScript, which unfortunately I don't have time to cover, that allow you to handle errors in a specific way. And if you're handling the error properly, you probably don't want to pause on that error happening because you're handling it and making sure it works properly in your code.

[00:04:03]
So I recommend leaving that unchecked and leaving the other one for uncaught exceptions checked just because it'll stop you when you get to those particular problems inside your code. Now let's go ahead and actually fix our code so it's not going to stop us a bunch of times and continue onward. Now the next thing I want to talk about is how you manage going through your different code. To do this, I'm going to copy over some code.

[00:04:23]
I'll tell you exactly what this code is doing, but just so we have a particular location of code to go through in our application. You can see here we have 3 functions. We have complex calculation, we have multiply, and we have math. The way our code is working is complex calculation is passing in 3 and 4, and then what we're doing is we're just calling the multiply function, we're calling the math function, and we're returning, adding those two different values together.

[00:04:45]
To be honest, it doesn't really matter what the actual code itself is doing inside these multiply or math functions, but essentially it's just some random code and calling different functions. Now if we make our debugger a little bit larger, you'll notice I specifically put a debugger statement at the top of my complex calculation, and I already showed you how clicking this continue button will just continue my code until I get to the next breakpoint, or if there are no breakpoints, it'll just resume my application.

[00:05:08]
But we also have these other buttons over here which allow you to do even more with your code. The very first one is called the step over function. What this does is if you are on a line that would normally lead to a function, you can completely step over that and not jump into that function. So here I'm on the line with this multiply function. Normally if I were to continue in my program, it would go into this multiply function and run that code, but I may not care about that multiply function when I'm doing my debugging, so I click step over.

[00:05:36]
It's going to run the code in multiply, and then it'll pause me on the very next line of my code. Let's say for example though, this math function, I really care about what's going on inside of here. I can use the step into function, which is this straight down arrow, and that'll actually jump me to the very first line in that function. So now my program has paused right here and I have access to all the different variables and everything that's going on inside this math function so I can see, "Hey, what is this value?" and so on.

[00:06:00]
And I can continue to step through this different content, so I'll step to the next line and so on. But at some point I may say, "You know what, I've seen everything that I want to see inside this math function. I just want to jump back to where I was." That's where this step out of function works. If I click on this, it'll immediately exit the current function I'm in and bring me to the very next line after that function is called.

[00:06:21]
So now it finished running that math function, gave me my particular result value, and it was just 64 in this case, and now it's on the very next line where it's returning, adding those two different things together. So you can use a combination of step over to skip functions, step into to jump into functions, and step out of to exit a function once you're done actually looking at what that function does.

[00:06:40]
Now we're just going to click resume so it's no longer paused on this particular page. We'll scroll down a little bit of a ways, and I want to talk about the difference between step versus step into. We're going to copy over this code again just so we have an example to work with. And this code is relatively straightforward. You can see we pause at the top, then we have a setTimeout which all it does is log out the text inside after 1 second, and here we log out the text after.

[00:07:05]
Now inside of our dev tools over here on the right-hand side, if we open this up, you'll notice we have that normal step function we've been talking about, step into, but we also have a function which is literally just called step, which may sound a little bit confusing. The step into function will step into things that are even asynchronous, so I'm on this setTimeout, and this happens after 1 second of a delay.

[00:07:26]
But if I click step into, what'll happen is it'll wait 1 whole second and then it'll put me directly inside here. So when I click on this, you'll notice it waits 1 second, and now after that 1 second, I'm inside of this code that's supposed to be running. Now if I were to restart our application by just refreshing our page and saving over here, you'll notice we're again stopped directly on that debugger line.

[00:07:46]
But if I use the step function, instead of stepping into the next function that we're going to be going to, it'll skip completely over any asynchronous code and just bring me to the next line of code that I have. So you can see here, step has just skipped the asynchronous code and brought me directly to right here inside my code. Relatively minor differences between the two, but depending on if you want to jump into that asynchronous code or not, you'll maybe want to use step into versus step.

[00:08:09]
Now continuing onward, I want to talk about how we can actually start to analyze the different variables and scope and everything inside of our application. Let's copy over what this particular code looks like because this gives us a good example of a lot of different types of scope. We have a window-level variable. We have a script variable here. We have this function, which is an outer function that contains some scope.

[00:08:27]
We have an inner function which uses closures to contain different pieces of scope, and we're using all of these different variables inside this inner function, and I'm pausing our execution directly inside this inner function. So if we bring over what our dev tools look like, you can see we have that exact same code which has all those different script variables inside of them, and you can see we're paused in our inner function.

[00:08:48]
Now if I make this a little bit wider, you can see this scope tab right here, and there's multiple different categories of scope. We have a local scope, we have our closure scope, which we've talked about. We have our script scope, and we have our global scope. Now specifically this script scope is only for our global scope that's not on the window object, so anything defined on the window object falls in this global scope.

[00:09:11]
So if I search here, we should eventually see a global var right there, global var, and that's whatever I set that variable to. Now some browsers may distinguish global and script scope, and some may combine them together into one. This thing that they call script scope is what I've been calling the global scope, essentially the scope that is anything that is outside of a scope. So in our case our script variable here is in that script scope.

[00:09:32]
But again, like I said, depending on the browser you use, they may give this a slightly different name. Next we have our closure scope. These are the things available in that closure. So we're inside our inner function, and our closure contains all the stuff from our outer function. So we have our outer variable as well as parameter 1 directly inside of that closure scope. And then the local scope is just whatever is in our current scope that we're inside of.

[00:09:53]
So in inner function we have parameter 2 and inner variable as our values that we have access to. And as we move through our code by stepping through the different lines we're accessing, these scope variables are automatically going to update for us with whatever the newest value for them is. So you can see everything inside of here is updating based on what values we have inside of where we are in our code.

[00:10:12]
So this is a great way to see what's going on in your code. And something else that's kind of cool is this watch section. If I expand this right now, I had just an example in there, but you can type in any expression you want. Just click this plus button, and now, for example, I can search for script var. And let's just add on some text at the end of that. There we go. Click enter, and that's going to return to me essentially the evaluation of this JavaScript function.

[00:10:35]
So it's going to evaluate whatever my script variable is and add a bunch of text onto the end of it. Generally you're probably not going to use it for this particular case, but if you want to keep track of what a variable is or maybe a complex evaluation of like a JavaScript function, you can do that inside this watch section, and as you navigate through your code and those different variables change, this watch value will also update with that information.

[00:10:57]
And once you're done, you can just click delete to completely get rid of it. Now let's just continue on with our execution here to move on to the next section that we want to talk about. And that is going to be all about the call stack. So if we just go back into this example and refresh our page. You'll notice that we actually have a call stack that we have access to, which is essentially as we've been talking about all the functions we call to get to this point.

[00:11:18]
So if we look inside of here, we have our call stack, which is our inner function, which is what we're inside of. To get to that point, we called that from inside of our outer function, so that our outer function is our next thing, and we call it outer function from our global scope, which is generally called anonymous because it doesn't have a function name. And the nice thing about this call stack is I can actually click on these and bring me to that exact point in my code, and it'll update all of my scope variables based on that.

[00:11:41]
So if I go to my inner scope, you can see I have access to the closure, while in my outer scope, I don't have access to that anymore. And in this anonymous scope I have access to even less. So it brings me to the exact point in the code where I call those different functions and updates all the information in my page to reference those particular values. So the call stack is a really great way to jump between those different points inside of my page.

[00:12:03]
Now I can also set advanced breakpoints. The main one you're probably going to be setting are DOM-based breakpoints. So if we come into our application on the elements tab, I can actually set a breakpoint on something. For example, I can right-click the body, go down to where it says break on, and I can break on subtree modification, attribute modification, or node removal. And these allow me to do different things based on how the DOM changes inside my application.

[00:12:28]
To give you an idea of the different types, a subtree modification means that an element that's a child was either added or removed. So if you add a child to a DOM element, it'll pause you directly in where the code added or removed that element. Attribute modification would be like if I change the attribute of something, for example, I changed the source of a script file, that's changing an attribute, and it'll pause me on the code that caused that to occur.

[00:12:48]
And node removal means I remove that particular element. So if I want to figure out why an element's being removed, I can throw an event listener on there for when it's removed, and it'll stop me on the code where that's removing it. I can also set up event listeners specifically on or breakpoints specifically on event listeners. So if I go back to that sources tab inside of this event listener breakpoint, you'll see I have a list of all the event listeners.

[00:13:10]
Let's say we want to search for click. I can come in here and click on that, and now anytime something in my code causes a click event listener to occur, it'll stop me exactly where that code is. So to see an example of what that looks like, let's just come in here and add some code for that. I believe I have something I can just copy over. There we go. So I can just paste in this code and now we can just give it a quick second and if I click on my page in my document, just like that, you can see now it stopped me directly inside of here where I clicked on that page.

[00:13:39]
That's the event listener it's listening for because I set up the breakpoint for that particular event listener. And if I want to stop listening for those, I can just toggle this to get rid of them, and now I'm no longer listening for those click event listeners. You can also set up conditional event listeners, so if I want to, I can come in here and click, and that just sets me a normal event listener.

[00:14:00]
But if I want a conditional one, I can right-click and click add conditional breakpoint. Here you can type in any JavaScript expression that you want. For example, I can say if 5 is greater than 6. Anything that you want and now as long as that evaluates to true, it'll stop me here and if it evaluates to false, it just pretends the breakpoint doesn't exist. This is great for only breaking if certain conditions are met inside your code, but it's not something I use super often.

Learn Straight from the Experts Who Shape the Modern Web

  • 250+
    In-depth Courses
  • Industry Leading Experts
  • 24
    Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now