Devtools analyse function calls and variables post-factum - javascript

I'm debugging a userscript, which is hard to debug, because the bug happens rarely and unpredictably (yet), and the function stack gets executed repeatedly (and the bug happens approximately once every 10-20 times). I cannot pause the devtools, otherwise the page will reload and the bug won't appear (so I cannot use breakpoints). Edit: even if I stop the page from reloading I still have to make user-input repeatedly and fast to cause the bug, so not possible to use breakpoints, because that would stop the bug from appearing.
One of the ways which I can think of is putting console.log in every function and logging variables and then searching through them to find where it went wrong. But it seems very tedious. In the performance section of devtools it's possible to record the process, and see the function calls, but it's impossible to see the variables.
Is there any way to go through the function call stack post-factum (maybe a tool other than devtools), seeing what the variables were equal to in every cycle? (And not only the current call stack, because it gets updated on every user input in my script). Or is console.logging my only option in this case?
I thought that "step out of the current function" option would work, but it seems to be unpredictable (it seemed to happen at least when there is setTimeout). And the function stack gets updated on every user input (and to capture this bug the user input sequence should be fast), so there is no way to go through the call stack either.
It would be perfect to have something like a call stack tree, which would show when a certain function was last called (and how many times during a certain period of time or since the page load), what was the position of this function in the tree of all functions, and the ability to go through this tree and search for all instances of calls to a specific function, and then the ability to see what the variables were equal to in every call.
There is a lot of code, but since it was requested, here is a link to the code inside a GitHub repository (it's a Chrome Extension, and the code where the bug happens is inside the objGA object [at the 6490's line of code]). And the bug happens somewhere between the 6600's line and the 6890's (the bug is that sometimes it doesn't move chess pieces on premoves). It's a Chrome Extension to move chess pieces with a keyboard and a mouse.
https://github.com/Sentero-esp12/Lichess-Keyboard-WebRequest-/blob/master/Extension/code.js
Edit:
Luckily I was able to reproduce it in a slow pace with breakpoints (was able to find the exact moment when the bug appeared). So it turned out I was using Math.round instead of Math.floor trying to extract the first digit from a double digit number. Since only some numbers were >= *5, the bug appeared only occasionally and I couldn't notice the cause.

Related

window.pageYOffset is sometimes 0 instead of a valid value

I'm having a problem where sometimes when my JavaScript in a Web page gets the value of window.pageYOffset it is inexplicably 0 even though I know the user is viewing the middle of the document and its value should be huge, like 650000. Note that a huge percentage of the time I get a reasonable value. But sometimes it's zero and sometimes it's a seemingly random small value, like in the 6000 range when I'm expecting 650000.
Rather than post a bunch of code, I'd like to ask some general questions to help me figure out where to begin to look.
This page is being displayed in an iOS WKWebView (though this problem can manifest in a similar context in an Android app). JavaScript methods in my app can be invoked in one of several ways:
When my app is notified that the page has finished loading (via a delegate method), it invokes a JavaScript method using evaluateJavaScript from the Objective-C code.
My app can call evaluateJavaScript at other times, not just when the page finishes loading.
A JavaScript function may be called as the result of a timer firing.
A JavaScript function may be called as the result of a scroll event.
I have been operating under the assumption that the JavaScript code on the page is always operating in a single thread. That is, I don't have a situation where a timer firing, a scroll event happening, or even a call from the Objective-C code (using evaluateJavaScript) is interrupting anything that might be happening in the JavaScript runtime. So I shouldn't have to worry about interrupting some system-level activity that is modifying window.pageYOffset while I'm trying to access it.
So that's my first question: Am I correct that someone outside my code is invoking my JavaScript methods on a single thread and not monkeying with the DOM on another thread?
My second question is related: My code modifies the DOM, adding and removing div elements. I've been assuming that those modifications are synchronous -- if I insert an element with insertAfter or insertBefore, I expect that the child/parent/sibling pointers are accurate upon return, and I assume that I can immediately access things like the top and left values on some other element and they will have been updated to reflect the inserted/removed element. The point being that I shouldn't have to "wait" for the DOM to "stabilize" after making changes and before checking something like window.pageYOffset. Is this correct?
One more clue: To help mitigate this, I have had good luck simply testing window.pageYOffset for zero at the top of a function. If it is zero, I call myself back on a timer (with just a 1 msec delay). If I do that long enough, it will eventually be non-zero.
Perhaps after reading all this, none of the detail is relevant and you know the answer to the basic question: Why do I sometimes get an invalid value (usually 0) in window.pageYOffset when the same line of code gives a valid value at other times.
The problem turned out to be that there appears to be a period of time between when I give the WKWebView a new HTML string to render and when it tells me that it is done loading the page that the existing page is still active. During this time, timers continue to fire, but some document and window properties will not be valid.
Because of the difficulty of debugging JavaScript running in this environment, I was tricking myself into thinking "eventually pageYOffset becomes valid" when in fact what I was seeing was that the new page eventually finished loading, and it was this new page that was generating valid calls to my timer functions.
In my particular case (may not work for everyone) I am able to detect the value of window.pageYOffset at the top of my timer function and if it is 0, call myself back after a brief delay. This allows me to handle the case where, for some reason, window.pageYOffset is just not yet valid (my test will eventually pass and my timer function will continue as usual) and the case where everything is in the process of being thrown away in favor of the new page (in which case the timer will not fire because the page goes away).

How to find the place where a certain function is called?

I'm writing a webpage, where I need to do some little changes. The problem is, I need to find the place, where one certain function is called (there are plenty of JavaScript files, so I'm not able to go through them line by line). Do you have any idea, how could I find it out?
I know how to do step-by-step debugging in Firebug or similar browser consoles, but still, I don't know how to recognize the place where the function was called.
I prefer working with consoles in Firefox or Chrome.
Debugging Tips For Chrome:
There are probably a number of ways you can find out where a change is coming from. But I find this one a time saver when it comes to tracking down changes in the DOM. (which will usually lead me to a function I am looking for)
Break on subtree modification or attribute modifications. To do this right click on an element in the DOM tree. Specifically the one you think the change is being applied to. From there you will get a context menu which will give you these options. Selecting either one with set a DOM breakpoint.
If this triggers the debugger you can then proceed to step through the code by using F11 and shift + F11 to skip over functions (useful if you wind up in a library like jQuery). While doing this, pay attention to the call stack. This will tell you where the code is coming from..
More in depth information:
https://developer.chrome.com/devtools/docs/javascript-debugging
To get to know the caller of a function just set a breakpoint at the first line of it. Once the breakpoint gets hit, you can see within the stack trace from where it was called.
Firefox DevTools
Firebug
Chrome DevTools
If you have access to the scripts, you could add at the end of every function you want to watch :
console.trace()
This will output in Chrome's console what function have been called with its position in the file (line number)

What in JavaScript can cause browser crashes?

I have an application that a wrote in straight JavaScript (no jQuery or anything). What it does is it uploads an image, and when you click on it, it gets the dominant colors of the image as well as picks the color you just clicked in the image, and generates a color scheme based on this.
I have part of it implemented here: http://cassidoo.co/assets/colordetect/index.html (this version only has the color detection part, not the color picker/color scheme part)
Now, I'm trying to figure out some issues. The application usually works. The only time it doesn't work is when the browser crashes. I looked at the thread here:
How can I test potentially "browser-crashing" JavaScript?
And I've been using my debugger and everything, but I'm not actually getting any errors when the browser crashes. It just suddenly isn't responsive and after a little while I get the "Oh, Snap" screen or something.
How can I debug this? What in my code might be freaking out (like is it an infinite loop I'm not closing, something with the canvas that's not normal)? Why does it only happen like 50-60% of the time? Is it a cache issue?
Do you have particular test images which always make it crash? If so, can you upload them somewhere so we can test with them?
I'm finding that it always crashes when trying to process an animated GIF. Using Chrome's debugger, I can see that it's getting into an infinite loop in the while (true) loop in k_mean(). The break condition diff < min_diff is never happening. Something's going wrong in the code, because diff is always NaN (not a number).
A good way to debug it is to set breakpoints at various places in the code, look at the state of the variables each time a breakpoint is triggered, etc. The profiler in Chrome can also be useful, by showing you where the execution time is being spent.
It probably is an infinite loop. You can test that by putting a condition in your loop that throws an alert or console-log after 100 loops (or whatever) and halts execution.
Any tricky regular expressions? Catastrophic backtracking can bring you down too. http://www.regular-expressions.info/catastrophic.html
And as mentioned above, too many recursions will also. Any functions calling themselves repeatedly?
You could always do something like this:
var foo = "bar";
while (1) {
foo = foo += "bar"; // adds until memory is full, then crashes (womp womp)
}
Here are some of the things that could cause browser crashes, although I am not sure if they are causing your problem.
Anything while(1) (infinite loop) - Browsers cant seem to handle these
Variable with too much data (out of memory - plausible if storing big images)
Trying to reload too many times (like infinite loop of realoads)
SetInterval to SetInterval To SetInterval etc... (this is more silly than a guess)
Probably an infinite loop or just a weird while. I hope you get it fixed!
Simplest way:
while(1)location.reload()
It works by creating an endless loop, then refreshes the page until the browser crashes.
Note: it instantly freezes and you can not see it refreshing.
Try it for yourself:
https://send-as-mail.000webhostapp.com/

Non-breaking breakpoints (trace points) in Javascript?

This is a rather complicated question that may simply be impossible with what's currently available, but if there was an easy way of doing it it would be huge.
I'm debugging some JavaScript in Chrome, and because it's very event-driven, I prefer to get trace reports of the code (what got called, etc.) instead of breakpoints. So wherever I leave a breakpoint, I'd like to see the local function name and arguments.
The closest I can get is to drop a conditional breakpoint in, like the following:
There are two big problems with this approach:
Pasting this into each breakpoint is too cumbersome. People would be far more likely to use it if it could be chosen as the default action for each breakpoint.
In Google Chrome, the log calls get fired twice.
Any ideas on a way to surmount either of these problems? I think it might be possible in IE with VS, but the UI there seems equally cumbersome.
IE11 now has "tracepoints", independent of Visual Studio. They do exactly what you asked for three years ago. I don't see them in Chrome or any other browsers yet, but hopefully they will catch on soon!
The best option I found was to edit the javascript code in Chrome's Javascript panel, adding a console.log.
It would only work after the page has been loaded (unless you can afford to put a break point after refresh and then add the logging lines) and (to be worse) you would have to do it each time you reload the page.
Good luck with your search!
I couldn't find something to do this, so I wrote my own.
Now, instead of constantly inserting and removing console.log calls, I leave the logging in and only watch it when necessary.
Warning: specific code below is untested.
var debug = TraceJS.GetLogger("debug", "mousemove");
$('div').mousemove(function(evt) {
debug(this.id, evt);
});
Every time the mouse is moved over a DIV, it generates a logevent tagged ["mousemove", {id of that element}]
The fun part is being able to selectively watch events. When you want to only see mousemove events for element #a, call the following in the console:
TraceJS('a');
When I want to see all mousemove events, you can call:
TraceJS('mousemove');
Only events that match your filter are shown. If you call TraceJS(no argument), the log calls stop being shown.

javascript pausing consistently. How do I find what is causing it to pause?

I've got a fairly ajax heavy site and I'm trying to tune the performance.
I have a function that runs between 20 & 200 times, depending on the user.
I'm outputting the time the function takes to execute via console.time in firefox.
The function takes about 4-6ms to complete.
The strange thing is that on my larger test with 200 or runs through that function,
it runs through the first 31, then seems to pause for almost a second before completing the last 170 or so.
However, that 'pause' doesn't show up in the console.time logs, and I'm not running any other functions, and the object that gets passed to the function looks the same as all other objects that get passed in.
The function is called like this
for (var s in thisGroup.events){
showEvent(thisGroup.events[s])
}
so, I don't see how or why it would suddenly pause near the beginning. but only pause once and then continue through.
The pause ALWAYS happens on the 31st time through the function.
I've taken a close look at the 'thisGroup.events[s]' that it is being run through, and it looks like this for #31
"eventId":"5106", "sid":"68", "gid":"29", "uid":"70","type":"event", "startDate":"2010-03-22","startTime":"6:00 PM","endDate":"2010-03-22","endTime":"11:00 PM","durationLength":"5", "durationTime":"5:00", "note":"", "desc":"event"
The event immediately after the pause, #32 looks like this
"eventId":"5111", "sid":"68", "gid":"29", "uid":"71","type":"event", "startDate":"2010-03-22","startTime":"6:00 PM","endDate":"2010-03-22","endTime":"11:00 PM","durationLength":"5", "durationTime":"5:00", "note":"", "desc":"event"
another event that runs through no problem looks like this
"eventId":"5113", "sid":"68", "gid":"29", "uid":"72","type":"event", "startDate":"2010-03-22","startTime":"4:30 PM","endDate":"2010-03-22","endTime":"11:00 PM","durationLength":"6.5", "durationTime":"6:30", "note":"", "desc":"event"
From the console outputs, it doesn't appear as there is anything hanging or taking up time in the function itself, as the console.time for each event including #31,32 is 4ms.
Another strange thing here is that the total time running the for loop across the entire object is coming out as 1014ms which is right for 200 events at 4-6ms each.
Any suggestions on how to find this 'pause'?
I find it very interesting that it is consistently happening between #31 & #32 only!
------------------- a bit of a hint on the problem, but no solution -------------------
if looks like this is a lag from the where I put the html into the dom.
I've stripped out all sorts of code, but when I remove
jQuery('div#holdGroups').append(putHtml);
That is when the lag stops.
Is there any way to do a clean-up or something on the append? I've tried .html, but that isn't any better, and append is really what I want.
I can do a solid 3 count during the pause, which really isn't good, and I can't get the pause to show up anywhere in the console or profile.
It shows the actual append only taking 117ms but it is a fairly large chunk of html with 6 tables, so I don't think that is too bad.
-------------- further update - maybe garbage collection?? -----------------------
As per a few of the answers below, this may be an issue with garbage collection, though I can't be positive.
I have attempted to delete variables which are being used, such as the variable which holds the html which is added to the dom via
delete putHtml;
as well as other variables, but this has not had any affect.
if the problem is with garbage collection, maybe I'm going about cleaning it up wrong?
Is there a better way to do this?
Is there a way to determine if garbage collection is in fact the issue?
Try using console.profile() rather than console.time(). This allows you to wrap the whole block and get a more detailed breakdown of what's going on.
console.profile('my profile');
for (var s in thisGroup.events){
showEvent(thisGroup.events[s]);
}
console.profileEnd('my profile');
Does it consistently happen between #31 and #32 across different browsers? My guess is that it has something to do with the garbage collector. Also, timing in browsers is notoriously bad. I would try different browsers. If it consistently happens there, then it might be worth looking deeper into that iteration of the code. Otherwise, if it is the GC, your best bet would be to reduce the number of objects you generate.
Try collecting logs in a variable [array?] and outputing them at the end. I once did a ajax heavy "thingy" and the logs kept popping up in the console long after everything was done. The console might be the source of the lag.
Would it be possible to change the order of the data to see if that changes when the pause is? If it does, then it surely must be caused by the data. If not, then I would try narrowing down the functionality called by commenting out blocks of code until you notice the lag disappear. Experiment with that and I think you could probably find what the trouble is.
Trying loading the page with Firebug closed, therefore NOT running. I chased down a lag for three hours related to the Datepicker just the other day which went away once I closed Firebug. I was very frustrated, but not I know so any time I lag using jQuery, I close Firebug to see if it's truly something coded wrong or just Firebug getting in the way.

Categories

Resources