How to find what code is run by a button or element in Chrome using Developer Tools
Alexander Pavlov's answer gets the closest to what you want.
Due to the extensiveness of jQuery's abstraction and functionality, a lot of hoops have to be jumped in order to get to the meat of the event. I have set up this jsFiddle to demonstrate the work.
1. Setting up the Event Listener Breakpoint
You were close on this one.
- Open the Chrome Dev Tools (F12), and go to the Sources tab.
- Drill down to Mouse -> Click
(click to zoom)
2. Click the button!
Chrome Dev Tools will pause script execution, and present you with this beautiful entanglement of minified code:
(click to zoom)
3. Find the glorious code!
Now, the trick here is to not get carried away pressing the key, and keep an eye out on the screen.
- Press the F11 key (Step In) until desired source code appears
- Source code finally reached
- In the jsFiddle sample provided above, I had to press F11 108 times before reaching the desired event handler/function
- Your mileage may vary, depending on the version of jQuery (or framework library) used to bind the events
- With enough dedication and time, you can find any event handler/function
4. Explanation
I don't have the exact answer, or explanation as to why jQuery goes through the many layers of abstractions it does - all I can suggest is that it is because of the job it does to abstract away its usage from the browser executing the code.
Here is a jsFiddle with a debug version of jQuery (i.e., not minified). When you look at the code on the first (non-minified) breakpoint, you can see that the code is handling many things:
// ...snip...
if ( !(eventHandle = elemData.handle) ) {
eventHandle = elemData.handle = function( e ) {
// Discard the second event of a jQuery.event.trigger() and
// when an event is called after a page has unloaded
return typeof jQuery !== strundefined && jQuery.event.triggered !== e.type ?
jQuery.event.dispatch.apply( elem, arguments ) : undefined;
};
}
// ...snip...
The reason I think you missed it on your attempt when the "execution pauses and I jump line by line", is because you may have used the "Step Over" function, instead of Step In. Here is a StackOverflow answer explaining the differences.
Finally, the reason why your function is not directly bound to the click event handler is because jQuery returns a function that gets bound. jQuery's function in turn goes through some abstraction layers and checks, and somewhere in there, it executes your function.
Solution 1: Framework blackboxing
Works great, minimal setup and no third parties.
According to Chrome's documentation:
Here's the updated workflow:What happens when you blackbox a script?
Exceptions thrown from library code will not pause (if Pause on exceptions is enabled), Stepping into/out/over bypasses the library code, Event listener breakpoints don't break in library code, The debugger will not pause on any breakpoints set in library code. The end result is you are debugging your application code instead of third party resources.
- Pop open Chrome Developer Tools (F12 or ⌘+⌥+i), go to settings (upper right, or F1). Find a tab on the left called "Blackboxing"
- This is where you put the RegEx pattern of the files you want Chrome to ignore while debugging. For example:
jquery\..*\.js
(glob pattern/human translation:jquery.*.js
) - If you want to skip files with multiple patterns you can add them using the pipe character,
|
, like so:jquery\..*\.js|include\.postload\.js
(which acts like an "or this pattern", so to speak. Or keep adding them with the "Add" button. - Now continue to Solution 3 described down below.
Bonus tip! I use Regex101 regularly (but there are many others: ) to quickly test my rusty regex patterns and find out where I'm wrong with the step-by-step regex debugger. If you are not yet "fluent" in Regular Expressions I recommend you start using sites that help you write and visualize them such as http://buildregex.com/ and https://www.debuggex.com/
You can also use the context menu when working in the Sources panel. When viewing a file, you can right-click in the editor and choose Blackbox Script. This will add the file to the list in the Settings panel:
Solution 2: Visual Event
It's an excellent tool to have:
Visual Event is an open-source Javascript bookmarklet which provides debugging information about events that have been attached to DOM elements. Visual Event shows:
- Which elements have events attached to them
- The type of events attached to an element
- The code that will be run with the event is triggered
- The source file and line number for where the attached function was defined (Webkit browsers and Opera only)
Solution 3: Debugging
You can pause the code when you click somewhere in the page, or when the DOM is modified... and other kinds of JS breakpoints that will be useful to know. You should apply blackboxing here to avoid a nightmare.
In this instance, I want to know what exactly goes on when I click the button.
-
Open Dev Tools -> Sources tab, and on the right find
Event Listener Breakpoints
: Expand
Mouse
and selectclick
- Now click the element (execution should pause), and you are now debugging the code. You can go through all code pressing F11 (which is Step in). Or go back a few jumps in the stack. There can be a ton of jumps
Solution 4: Fishing keywords
With Dev Tools activated, you can search the whole codebase (all code in all files) with ⌘+⌥+F or:
and searching #envio
or whatever the tag/class/id you think starts the party and you may get somewhere faster than anticipated.
Be aware sometimes there's not only an img
but lots of elements stacked, and you may not know which one triggers the code.
If this is a bit out of your knowledge, take a look at Chrome's tutorial on debugging.
Sounds like the "...and I jump line by line..." part is wrong. Do you StepOver or StepIn and are you sure you don't accidentally miss the relevant call?
That said, debugging frameworks can be tedious for exactly this reason. To alleviate the problem, you can enable the "Enable frameworks debugging support" experiment. Happy debugging! :)
You can use findHandlersJS
You can find the handler by doing in the chrome console:
findEventHandlers("click", "img.envio")
You'll get the following information printed in chrome's console:
- element
The actual element where the event handler was registered in - events
Array with information about the jquery event handlers for the event type that we are interested in (e.g. click, change, etc) - handler
Actual event handler method that you can see by right clicking it and selecting Show function definition - selector
The selector provided for delegated events. It will be empty for direct events. - targets
List with the elements that this event handler targets. For example, for a delegated event handler that is registered in the document object and targets all buttons in a page, this property will list all buttons in the page. You can hover them and see them highlighted in chrome.
More info here and you can try it in this example site here.
This solution needs the jQuery's data method.
- Open Chrome's console (although any browser with jQuery loaded will work)
- Run
$._data($(".example").get(0), "events")
- Drill down the output to find the desired event handler.
- Right-click on "handler" and select "Show function definition"
- The code will be shown in the Sources tab
$._data()
is just accessing jQuery's data method. A more readable alternative could be jQuery._data()
.
Interesting point by this SO answer:
As of jQuery 1.8, the event data is no longer available from the "public API" for data. Read this jQuery blog post. You should now use this instead:
jQuery._data( elem, "events" );
elem should be an HTML Element, not a jQuery object, or selector.Please note, that this is an internal, 'private' structure, and shouldn't be modified. Use this for debugging purposes only.
In older versions of jQuery, you might have to use the old method which is:
jQuery( elem ).data( "events" );
A version agnostic jQuery would be: (jQuery._data || jQuery.data)(elem, 'events');