DEV Community

Cover image for Bugs: Sane Debugging
bob.ts
bob.ts

Posted on • Updated on

Bugs: Sane Debugging

"Debuggers don't remove bugs. They only show them in slow motion." - Unknown

All modern browsers and most other environments support “debugging” ... a special UI in the Developer Tools that makes finding and fixing errors much simpler.

Within this article, I will be discussing Chrome (and my experiences); It is probably the most feature-rich browser in this respect.

To turn on developer tools, press F12 (Mac: Cmd+Opt+I).

When in the console tool, the following methods are available:

  • Viewing logged messages
  • Running JavaScript
  • Using console utilities to interact with the browser.

Viewing Logged Messages

Front-End Developers often log messages to the console to ensure that their JavaScript is working as expected. To log a message, they can insert an expression like

console.log('Hello, Console!')

into the JavaScript. When the JavaScript executes and sees an expression like that, it knows that it's supposed to log the message to the console.

The console.log can be indicating that the code reached a certain point; it can also be used to show the state of some variable(s). Messages are logged for two general reasons:

  • Ensuring the code is executing in the right order.
  • Inspecting the values of variables at a certain moment in time.

Of the console API options for Logged Messages, here are a few use cases:

  • console.count can be used to see how many times a function is called and some code iterated over.
  • console.group and console.groupEnd can be used to create a "summary of a process. Remember here that groups can be nested ... this can be very effective in a good logging tool.
  • console.table can be used to display tabular data more effectively.
  • console.time and console.timeEnd can be used very effectively to track performance of various processes.

Running JavaScript

The Console is also a REPL (Read-Eval-Print-Loop): A simple, interactive computer programming environment that takes single user inputs (i.e., single expressions), evaluates (executes) them, and returns the result to the user. JavaScript can be run in the console to interact with the page being inspected.

There is a solid interactive tutorial here ... Get Started With Running JavaScript In The Console

Logging Messages (console API)

The console API is used to write messages to the console from within JavaScript code.

console.assert(expression, object)

Log level: Error

Writes an error to the console when expression evaluates to false.

Visual of Assert

console.clear()

Clears the console.

If Preserve Log is enabled, console.clear() is disabled.

console.count([label])

Log level: Info

Writes the number of times that count() has been invoked at the same line and with the same label. Call console.countReset([label]) to reset the count.

Visual of Count

console.countReset([label])

Resets a count.

console.debug(object [, object, ...])

Log level: Info

Identical to console.log(object [, object, ...]).

Visual of Debug

console.dir(object)

Log level: Info

Prints a JSON representation of the specified object.

Visual of Dir

console.dirxml(node)

Log level: Info

Prints an XML representation of the descendants of node.

Visual of Dirxml

console.error(object [, object, ...])

Log level: Error

Prints object to the Console, formats it as an error, and includes a stack trace.

Visual of Error

console.group(label)

Visually groups messages together until console.groupEnd(label) is called. Use console.groupCollapsed(label) to collapse the group when it's initially logged to the Console.

Visual of Group

console.groupCollapsed(label)

Same as console.group(label), except the group is initially collapsed when it's logged to the Console.

console.groupEnd(label)

Stops visually grouping messages.

(see console.group)

console.info(object [, object, ...])

Log level: Info

Identical to console.log(object [, object, ...]).

console.log(object [, object, ...])

Log level: Info

Prints a message to the Console.

Visual of Log

console.table(array)

Log level: Info

Logs an array of objects as a table.

Visual of Table

console.time([label])

Starts a new timer. Call console.timeEnd([label]) to stop the timer and print the elapsed time to the Console.

Visual of Time

console.timeEnd([label])

Log level: Info

Stops a timer.

(see console.time)

console.trace()

Log level: Info

Prints a stack trace to the Console.

Visual of Trace

console.warn(object [, object, ...])

Log level: Warning

Prints a warning to the Console.

Visual of Warn

Console Utilities

These are some of the utilities available that I have found useful in debugging ...

$_

$_ returns the value of the most recently evaluated expression.

$0 - $4

The $0, $1, $2, $3 and $4 commands work as a historical reference to the last five DOM elements inspected within the Elements panel or the last five JavaScript heap objects selected in the Profiles panel. $0 returns the most recently selected element or JavaScript object, $1 returns the second most recently selected one, and so on.

$(selector, [startNode])

$(selector) returns the reference to the first DOM element with the specified CSS selector. This function is an alias for the document.querySelector() function.

Right-click on the returned result and select 'Reveal in Elements Panel' to find it in the DOM, or 'Scroll in to View' to show it on the page.

This function also supports a second parameter, startNode, that specifies an 'element' or Node from which to search for elements. The default value of this parameter is document.

If you are using a library such as jQuery that uses $, this functionality will be overwritten, and $ will correspond to that library's implementation.

$$(selector, [startNode])

$$(selector) returns an array of elements that match the given CSS selector. This command is equivalent to calling document.querySelectorAll().

This function also supports a second parameter, startNode, that specifies an element or Node from which to search for elements. The default value of this parameter is document.

copy(object)

copy(object) copies a string representation of the specified object to the clipboard.

The object copied can then be pasted anywhere appropriate.

debug(function)

When the specified function is called, the debugger is invoked and breaks inside the function on the Sources panel allowing to step through the code and debug it.

debug(getData);
Enter fullscreen mode Exit fullscreen mode

Use undebug(fn) to stop breaking on the function, or use the UI to disable all breakpoints.

dir(object)

dir(object) displays an object-style listing of all the specified object's properties. This method is an alias for the Console API's console.dir() method.

dirxml(object)

dirxml(object) prints an XML representation of the specified object, as seen in the Elements tab. This method is equivalent to the console.dirxml() method.

inspect(object/function)

inspect(object/function) opens and selects the specified element or object in the appropriate panel: either the Elements panel for DOM elements or the Profiles panel for JavaScript heap objects.

getEventListeners(object)

getEventListeners(object) returns the event listeners registered on the specified object. The return value is an object that contains an array for each registered event type (click or keydown, for example). The members of each array are objects that describe the listener registered for each type.

If more than one listener is registered on the specified object, then the array contains a member for each listener.

monitor(function)

When the function specified is called, a message is logged to the console that indicates the function name along with the arguments that are passed to the function when it was called.

Use unmonitor(function) to cease monitoring.

monitorEvents(object[, events])

When one of the specified events occurs on the specified object, the Event object is logged to the console. You can specify a single event to monitor, an array of events, or one of the generic events "types" mapped to a predefined collection of events.

My General Practices

  1. Set up different log levels (error, debug, warning, etc.).
  2. Make it simple to turn debug logging on and off.
  3. Make it easy to trigger notifications of rare events.
  4. Use human-readable message encodings (like JSON).
  5. Organize application state well.
  6. Send stack-traces for infrequent errors somewhere.
  7. Add a means to view running state of the application.
  8. Good comments and documentation!

My Use-Cases (Go-To Functionality)

Debugging [di:b^g-ing]

  1. Being the detective in a crime where you are also the murderer.

Here, I'll list the "go-to" functionality that I use when debugging in the console.

console

The main use case here would be a LOGGING service that can be turned off and on via a value stored in Local Storage. This logging is invaluable when examining complex logic for some failure.

Note that console.group and console.groupEnd can can add a deeper level of understanding to the information provided.

When creating a PROFILING service, take a look at **console.time* and console.timeEnd; they can provide a solid set of timing that is significantly easier to manage than something homegrown.

console.log

There is an interesting use case for console.log is to wrap the values in brackets { }, utilizing the key/value naming via property value shorthand to give something like the following:

Object, Property Value Shorthand

copy

Using copy will allow for complex structures to be copied and placed into an editor for closer inspection. This tool can be invaluable.

Conclusion

All modern browsers and most other environments support “debugging” ... a special UI in the Developer Tools that makes finding and fixing errors much simpler.

These are some of the major parts of the console that I use ... some of the use-cases have been documented here. We aren't trying to remove bugs with the console tools; simply slow them down.

Top comments (0)