
Super Power Chrome DevTools

I work in a team Online. We are making a web version of the 2GIS directory. This is a long-lived actively developing project in which JavaScript is used as the main language both on the client and on the server.
An important place in the work is occupied by the analysis and debugging tools of the application. Popular JavaScript frameworks usually have their own tools tailored to a specific ideology. Our situation is complicated by the fact that under the hood of the on-line, a framework of our own production is buzzing - Slot - which is also under active development.
In this article, I will describe how we use standard browser-based developer tools for effective debugging and research. These recipes are aimed primarily at studying the application from the inside out, so they are suitable for any project.
Problem
The development dynamics does not allow team members to fully immerse themselves in the details of each other's tasks. The context of a particular component quickly eludes; Returning to the code section after a month, you may not recognize it. In addition, the team is constantly updated with new recruits.
In such a situation, it is necessary to quickly restore understanding of the logic of what is happening in the code. Given the variability of the project, this task is more of a research nature. Understanding the general principles of work, you still each time become the discoverer of specific aspects of implementation.
Debugging
Price for development speed - the presence of bugs. This class of tasks requires a quick response, and hence entry into the context of what is happening.
Invalid output
Often a bug manifests itself in some incorrect external event: an unexpected change in the DOM tree, an asynchronous request with erroneous data, etc. In this case, it is convenient to consider the application code as a black box, the input of which is the usage scenario, and the output is the result of a bug.
In addition to standard breakpoints on a line of code, DevTools (hereinafter referred to as Google Chrome browser tools) has the ability to stop execution on a specific event.
DOM Breakpoint is installed on the tree node in the inspector. You can stop when you delete this element, change its subtree or attributes (I recall that style and class are also attributes).

XHR Breakpoint is installed on the entire document and allows you to find a line of code from which a request matching a given pattern is sent.

These breakpoints work great in conjunction with the asynchronous call stack mode ( Async call stack ). It does not break off on asynchronous operations and makes it possible, for example, to switch from the setTimeout handler to the code that installed it. Thus, you can look much further into history and find the roots of even complex bugs.

Example scenario:
1. An unexpected change occurs in the DOM tree.
2. The behavior is reproduced.
3. Set the desired type of DOM-breakpoint.
4. Turn on Async mode in the debugger.
5. We reproduce the bug and travel through the call history until we find the roots of the problem.
Incorrect internal representation
Not all bugs are visible to the naked eye. During execution, only the internal state can change, which will later affect the behavior of the system as a whole. You can catch incorrect changes in this state using imagination.
Suppose a state is a global object. Then, to track him, you can use the following code:
var watchMe = {};
Object.observe(watchMe, function() {
debugger;
});
watchMe.foo = ‘bar’; // Выполнение остановится
Using the advanced features of the console (which are described in detail later), you can add change logging without stopping execution for everyone.
var watchMe = {};
Object.observe(watchMe, function(options) {
options.forEach(function(option) {
var groupName = option.name + ' changed';
console.groupCollapsed(groupName);
console.log('Old value: ', option.oldValue);
console.log('New value: ', option.object[option.name]);
console.groupEnd(groupName);
});
});
This example will display the Chrome console compact log groups when changing the properties of an object. The code is now much larger, and each time writing it from memory is not convenient. Therefore, you can save it as a snippet and run it as needed.

Of course, this code will have to be adapted each time to the project and task. Rarely, all state is stored in one global object. Sometimes you have to edit the source code to wedge into the execution context. But the benefits of this approach are worth the effort.
Usage scenario:
1. If the observed object is global, then just run the snippet on it.
2. If the object is available only in the local scope, add the desired code to the application for debugging.
Study
The work of a programmer is not limited to fixing bugs. To add new functionality, it is important to understand how the application as a whole works in complex scenarios.
Console as a source of knowledge
The console in DevTools is not only a way to quickly execute a small script. It has a powerful API that implements inaccessible in the language convenient functions and links with other DevTools tools.
For example, to output a DOM element to the console, it is not necessary to use complex selectors. Instead, a stack of items selected in the inspector is implemented within the console. Access to it occurs through the command $ N, where N is the indent from the end of the stack. Thus, accessing $ 0 in the console will return the last DOM node selected in the inspector, $ 1 - the penultimate one, and so on.
It is convenient to use this feature in conjunction with functions over DOM nodes:
- monitorEvents (object) - monitors element events;
- getEventListeners (object) - displays in the console a list of event handlers for the element from which you can go to the function code.
A simple scenario emerges:
1. Select the elements in the inspector.
2. We call the necessary command in the console, pass $ 0 as an argument.
3. Rejoice, like children.
Many developers remove console.log () from the code immediately after debugging. But some key functionality requires constant logging. As a result, each developer first writes debugging code, and then deletes it.
There is a way to prevent output to the console on production and at the same time it is convenient to log what is happening at the development stage. We use UglifyJS to compress JavaScript, and it has the option of overriding the values of global variables.
// Конфиг UglifyJS
global_defs: {
DEBUG: false
}
// Где-то в коде приложения
if (DEBUG) {
console.log(‘Что-то важное’);
}
In the example above, DEBUG will not just be false after the build. UglifyJS will understand that the condition will never be fulfilled, and simply remove it from the code.
Now you can use the more complex console output capabilities for different data types. In the state debugging example, the output will be more compact due to console.groupCollapsed. This is used in our project to track URL changes:

console.table is good for arrays. A complete list of output options is here .
Bird's-eye
The built-in browser-level event logging tool is Timeline. Until recently, it could be used to analyze application performance. With the advent of experimental functions, its capabilities have expanded significantly.
One of the long-awaited features is the display of call stacks directly in the event diagram. Essentially, this combines the classic Timeline with a CPU Profiler report. Such a diagram gives an understanding of how the application works in dynamics: sequence of calls, total execution time of functions, points of interaction of JavaScript with the DOM. Even when there is no need for optimization, it can be used to study the internal structure of the project.

If you are interested in a specific section of the application logic, and there are too many events in the report, you can use console.time. In addition to measuring the runtime, this method adds a label to the Timeline.

Usage example:
1. We write a user script.
2. We study call stacks.
3. If necessary, go to a specific line of code directly from Timeline.
4. If there is too much information, we wrap the code of interest in console.time and console.timeEnd.
5. Repeat until a complete understanding of the logic of what is happening.
Conclusion
When working on large projects, it makes sense to invest time in the convenience of development. Hours spent on learning and adapting tools save debugging days and give a better understanding of the project.
This article describes only a small fraction of the capabilities of Chrome Developer Tools. In working on 2GIS Online, we have more exotic tasks that require constant study of new development tools. In more detail about these tools, and also about productivity of applications on JavaScript, I spoke at the FrontTalks conference.