How can you debug JavaScript which hangs the browser? - javascript

I'm working on a substantially large rich web page JavaScript application. For some reason a recent change is causing it to randomly hang the browser.
How can I narrow down where the problem is? Since the browser becomes unresponsive, I don't see any errors and can't Break on next using FireBug.

Instead of commenting the hell out of your code, you should use a debug console log.
You should use the console.log() functionality provided by most modern browsers, or emulate it if you use a browser that doesn't support it.
Every time you call console.log('sometext'), a log entry in the debug console of your browser will be created with your specified text, usually followed by the actual time.
You should set a log entry before every critical part of your application flow, then more and more until you find down what log isn't being called. That means the code before that log is hanging the browser.
You can also write your own personal log function with added functionalities, for example the state of some particular variable, or an object containing a more detailed aspect of your program flow, etc.
Example
console.log('step 1');
while(1) {}
console.log('step 2');
The infinite loop will halt the program, but you will still be able to see the console log with the program flow recorded until before the program halted.
So in this example you won't see "step 2" in the console log, but you will see "step 1". This means the program halted between step 1 and step 2.
You can then add additional console log in the code between the two steps to search deeply for the problem, until you find it.

I'm surprised this hasn't been properly answered yet, and the most voted answer is basically "put console logs everywhere until you figure it out" which isn't really a solution, especially with larger applications, unless you really want to spend all your time copy-pasting "console log".
Anyways, all you need is debugger; someone already mentioned this but didn't really explain how it could be used:
In chrome (and most other browsers), debugger; will halt execution, take you to the dev console, and show you the currently executing code on the left and the stack trace on the right. At the top right of the console there are some arrow like buttons. The first one is "resume script execution". The one we want is the next one "step over next function call".
Basically, all you need to do is put a debugger anywhere in your code, at a point where you know the page hasn't frozen yet, and then run it, and repeatedly click "step over next function call" which looks like an arrow jumping over a circle. It will go line by line, call by call, through the execution of your script until it hangs/gets stuck in an infinite loop. At this point, you will be able to see exactly where your code gets stuck, as well as all the variables/values currently in scope, which should help you understand why the script is stuck.
I was just racking my brain trying to find a hanging loop in some rather complex JS I'm working on, and I managed to find it in about 30 seconds using this method.

You can add debugger; anywhere in your JS code to set a breakpoint manually. It will pause execution and allow you to resume/inspect the code (Firebug/FF).
Firebug Wiki page: http://getfirebug.com/wiki/index.php/Debugger;_keyword

Todays browsers Firefox/Seamonkey (Ctrl-Shift-I / Debugger / PAUSE-Icon), Chrome, ... usually have a builtin JS debugger with PAUSE button which works any time. Simply hit that when on a looping / CPU-intensive page, and most likely the "Call Stack" kind of pane will point you to the problem - ready for further inspection ...

To isolate the problem you could start by removing/disabling/commenting different sections of your code until you have narrowed down the code to a small part which will allow you to find the error. Another possibility is to look at your source control check-in history for the different changes that have recently been committed. Hopefully you will understand where the problem comes from.

Install Google Chrome, go to your page, press f12 and the developer console will popup. Then select the Scripts button, then select your script (ex: myScript.js) from the dropdown in the top-left of the console. Then click on the first line (or a line where you think don't hangs) and a break-point will be made. After the javascript reaches your break-point click on one of the buttons of the top-right of the console (you will see a button like Pause symbol and then other 4 button). Press on the 2º button (or the button after pause to step over) or the 3º button (step in). Mouse over the buttons and they will explain to you what they mean.
Then you will go in your code like this until it hangs and then you can debug it better.
Google Chrome debugger is far better than firebug and faster. I made the change from firebug and this is really great! ;)

I know it's primitive, but I like to sprinkle my js code with 'alert's to see how far my code is going before a problem occurs. If alert windows are too annoying, you might setup a textarea to which you can append logs:
<textarea id='txtLog' ...></textarea>
<script>
...
function log(str) {
$('#txtLog').append(str + '\n');
}
log("some message, like 'Executing Step #2'...");
...
</script>

In my experience, issues which cause the browser to become unresponsive are usually infinite loops or the suchlike.
As a start point, investigate your loops for silly things like not incrementing something you later rely on.
As an earlier poster said, other than that, comment out bits of code to isolate the issue. You 'could' use a divide and conquer methodology and near literally comment out half the pages JS, if it worked with a different error, you've probably found the right bit!.
Then split that in half, etc etc until you find the culprit.

I think you can Use Console Log like this
console.log(new Date() + " started Function Name or block of lines from # to #");
// functions or few lines of code
console.log(new Date() + " finished Function Name or block of lines from # to #")
By the end of running your webpage, you can identify the area that take so much time during executions, b

Besides using manual log output and the debugger it might sometimes be helpful to log each and every function call to track down where the loop occurs. Following snippet from Adding console.log to every function automatically might come in handy to do so ...
function augment(withFn) {
var name, fn;
for (name in window) {
fn = window[name];
if (typeof fn === 'function') {
window[name] = (function(name, fn) {
var args = arguments;
return function() {
withFn.apply(this, args);
return fn.apply(this, arguments);
}
})(name, fn);
}
}
}
augment(function(name, fn) {
console.log("calling " + name);
});

I know this question is old, but in VS2013 and you can press the pause button and get a full JS stack trace. This was driving me crazy because the loop was inside angular, so I couldn't really put in alerts, break points, etc. because I had no idea where to put them. I don't know if it works with the free express edition, but it's worth a shot.
I've also read that Chrome has a pause function, so that could be an option, but I haven't tried it myself.

I ran into same problem and that's how I resolved it.
Check Console for errors and fix them
Some time console even is hanging
Check for all the loops if the one is infinite
Check for recursive code
Check for the code which is dynamically adding elements to document
Use break points in your console
Use some console logging i.e log the suspected code blocks

Something I don't really see in these answers is that you can do e.g.:
let start;
let end;
//This would represent your application loop.
while (true) {
start = performance.now();
//Loop code.
//...
end = performance.now();
//Measured in ms.
if (end - start > 1000) {
//Application is lagging! Etc.
}
}
In this manner, you can perhaps detect when your application is starting to perform poorly etc.
https://developer.mozilla.org/en-US/docs/Web/API/Performance/now

Related

Is there any chance to find source of javascript alert?

I'm working in a large project that was developed for several years and had tons of code. Recently uninformative alert start to appear. It just says Undefined. I need to find the source of this alert. Is the any chance to make something like "breakpoint on alert"? I want to see the source of this alert.
One possibility is to redefine alert function. I tried to make it in firefox without any success.
I'd go with redefining window.alert right at the start of the code for this type of development purposes.
window.alert = function(e){ console.warn( "Alerted: " + e ); }
This will give You a line number for sure. ( Tested on chrome console )
This is an old question, but thought I would help out with a simpler solution. A very easy way in Chrome to find the source is by placing a debug in the console on window.alert:
debug(window.alert)
This will break on alert and take you to the source. In general, using console with debug(fname) will break whenever the function fname is called.
As a continuation to Vsevolod's method, in FireBug over Firefox for example, you could place one conditional breakpoint on each and every alert(), and see which one fires off, then go up the callstack shown by FireBug.
The condition could be "typeof whatever_variable_is_displayed == 'undefined'".

Is there a way to track an infinite loop with console.log or something alike?

i was wondering if there is any way of tracking an infinite loop in javascript/jquery ?
I am working on a jsTree plugin clone sort of.. (why isn't important) and I've create a infinite loop somewhere and i am trying to track where it happened. i thought maybe there are browser specific tricks to track infinite loops
E.G
<div id="someAwesomeDiv"></div>
jQuery(document).ready(function ($) {
var i = 0;
while(i < 10){
console.log(i);
$('#someAwesomeDiv').append('<br>i</br>')
i--;
}
});
when i refresh this page.. nothing is appended to the div nor does it console.logged, the page just freezes.
Thanks in advanced.
That is the supposed behaviour. Your are cogging the JS engine with your infinite loop, it's busy doing that rather then rendering (both page and console in dev tool window).
If you're having difficulty finding and diagnosing infinite loops by throwing console.log calls into all your suspect loops, try using alert and confirm instead. While console.log can be somewhat uncooperative (or, by the sounds of it, completely non-functional) when the browser is stuck in an infinite loop, alert will always work immediately.
With confirm, you can even go one step better and have the option of breaking out of the loop. For example, here is your example code modified to let you break out of the loop at any time.
jQuery(document).ready(function ($) {
var i = 0;
while(i < 10){
if (confirm("i = " + i + "; break the loop?")) {
throw new Error("Loop broken by manual user override");
}
$('#someAwesomeDiv').append('<br>i</br>')
i--;
}
});
(Fiddle).
Then if you hit the infinite loop, you can choose to throw an error and hopefully (unless it gets caught, or the same code is immediately triggered again) regain control of the window and be left free to play around in the window and the console and try to figure out what was going on the cause the loop.
Two word of caution, though: in some browsers, alert and confirm can sometimes make weird stuff happen in your code by screwing up the expected order of execution when, for instances, DOM events get triggered during an alert, as bobince describes in detail here: https://stackoverflow.com/a/2734311/1709587. They can potentially help you in infinite loops where console.log is trickier to wield, but make sure you don't get tripped up by behavior changes introduced by putting alerts into your code. Also note that reflows happen when you trigger an alert, which can change the behavior of code involving CSS transitions.
Also, I'm really not sure why you're not getting any output in the console from the sample code you've given. When I paste it into a jsFiddle and try it on Chrome, and then load the fiddle with the console open, the page is slow and unkillable and the whole browser a little buggered, but I do see things being logged (admittedly only every thousand lines or so). In Firefox, nothing happens for 5 seconds or so, but then I get an 'unresponsive page' popup and the option to kill the running script - after which I can see everything that was logged in the console. Perhaps trying a different browser (or the latest version of whatever browser you use) will make life easier for you without needing to deploy any tricks?

Pausing/Breaking execution in javascript for debugging, but only for certain javascript files

Do any browsers support pausing execution / stepping through code, but only for certain files or regions? I'm using jQuery and several other libraries, and I'm not interested in stepping through their code in 99% of cases, as it is my code that is wrong. All my code is in my script file, other libraries are included separately.
If I use the pause button, I tend to find that I am very quickly taken to some part of jquery with code I don't understand or need to understand. If I click the step into button a lot, I sometimes get taken to a point in my script, sometimes not.
I could manually click every single line of my code to add a breakpoint, but this would be extremely tedious, and I couldn't un-pause execution easily. If there is a browser that lets you select multiple lines and add breakpoints to all of them in one click, that would be a great alternative, though.
There are some new features in the Chrome developer tools that can help you get a good entry point into a new code base. Event listener breakpoints will let you pause execution at a given event handler:
Things have changed since I asked the question 5 years ago. Chrome (and possibly other browsers) have an option "Blackbox script". If you find yourself paused inside a library, e.g. jQuery, right click, choose "Blackbox script" and you will automatically skip over all lines in that file when you are stepping through the code in future.
This is what step in/over/out is for. If the program is stopped for debugging, and you're stepping through and see that you're about to descend into a jQuery function (or anything else you want to skip over) you click "step over". If you got into something which you want to get right back out of, you click "step out".
Simply set the breakpoint where you want to begin debugging, and use the step functions from there to control what you're stopping to take a look at.
Put the break points in the desired javascript files and where you want to inspect your code!
Press this will let you skip the jumping to other files and you will be able to continue in the same JS file

Using WebInspector's Javascript Debugger, how do I break out of an infinite loop?

I wrote an infinite loop in my javascript code. Using WebKit's Web Inspector, how do I terminate execution? I have to quit Safari and reopen it again (after changing my code of course).
EDIT: To be more specific, I'm looking for a way to enter the looping executing process/thread to see why the loop isn't terminating. An analogy would be in GDB where I could do a ^C and break into the process. I'm not looking for a way to kill my web browser. I'm pretty good at that already.
I'm not familiar with WebKit, but this sounds like a common problem that I usually debug as follows: Declare an integer outside of the scope of the loop, and increment it for each iteration, then throw an exception when the iteration count exceeds the maximum expected possible amount of iterations. So, in pseudo-code, something like the following could be used to debug this problem:
var iterations = 0;
var greatestPossibleNumberOfValidIterations = 500;
while(shouldLoopBooleanTest){
iterations++;
if(iterations>greatestPossibleNumberOfValidIterations){
//do debugging/error handling
}
}
I don't expect that this is specific enough to warrant an accepted answer, but I hope it helps you solve your problem.
Have you tried top to look at the process tree? Find the PID of the program and then type kill -9 [PID].
Have you tried using F11? This is the key for step into: https://trac.webkit.org/wiki/WebInspector
In using Firefox (I know the question doesn't specify Firefox, but I'm just throwing this in, in case it helps somebody), Safari, and Chrome, I found that there isn't a consistent way to break into an infinite loop, but there are ways to setup execution to break into a loop if you need to. See my test code below.
Firefox
Utter trash. It just stood there spinning it's rainbow. I had to kill it.
Safari
The nice thing about Safari is that it will eventually throw up a dialog asking if you want to stop. You should say yes. Then hit command-option i to bring up the Web Inspector. The source should pop-up saying that the Javascript exceeded the timeout. Hit the pause button in the right hand side towards the top, then refresh. The code will reload, now step through: I like using command-; because it steps through every call. If you have complex code you might never get to the end. Don't hit continue though (command-/) or you'll be back at square one.
Chrome
The most useful of the three. If you naively load the code, it will keep going forever. But, before loading the page, open the Web Inspector and select 'Load resources all the time'. Then reload the page. While the page is trying to load, you can click over to scripts and pause the Javascript while it is running. This is what I was looking for.
Code
<html>
<head></head>
<body onload="TEST.forever.loop()">
Nothing
</body>
<script type="text/javascript">
TEST = {};
TEST.forever = {
loop : function() {
var i = 0;
while (i >= 0) {
i++;
}
}
};
</script>
</html>

Javascript: Unresponsive script error

I get an error message from Firefox "Unresponsive script". This error is due to some javascript I added to my page.
I was wondering if the unresponsiveness are caused exclusively by code loops (function calling each other cyclically or endless "for loops") or there might be other causes ?
Could you help me to debug these kind of errors ?
thanks
One way to avoid this is to wrap your poor performant piece of code with a timeout like this:
setTimeout(function() {
// <YOUR TIME CONSUMING OPERATION GOES HERE>
}, 0);
This is not a bullet proof solution, but it can solve the issue in some cases.
According to the Mozzila Knoledgebase:
When JavaScript code runs for longer than a predefined amount of time, Firefox will display a dialog that says Warning: Unresponsive Script. This time is given by the settings dom.max_script_run_time and dom.max_chrome_script_run_time. Increasing the values of those settings will cause the warning to appear less often, but will defeat the purpose: to inform you of a problem with an extension or web site so you can stop the runaway script.
Furthermore:
Finding the source of the problem
To determine what script is running too long, click the Stop Script button on the warning dialog, then go to Tools | Error Console. The most recent errors in the Error Console should identify the script causing the problem.
Checking the error console should make it pretty obvious what part of your javascript is causing the issue. From there, either remove the offending piece of code or change it in such a way that it won't be as resource intensive.
EDIT: As mentioned in the comments to the author of the topic, Firebug is highly recommended for debugging problems with javascript. Jonathan Snook has a useful video on using breakpoints to debug complex pieces of javascript.
We need to follow these steps to stop script in Firefox.
Step 1
Launch Mozilla Firefox.
Step 2
Click anywhere in the address bar at the top of the Firefox window, to highlight the entire field.
Step 3
Type "about:config" (omit the quotes here and throughout) and press "Enter." A "This might void your warranty!" warning message may come up; if it does, click the "I'll be careful, I promise!" button to open the page that contains all Firefox settings.
Step 4
Click once in the "Search" box at the top of the page and type "dom.max_script_run_time". The setting is located and displayed; it has a default value of 10.
Step 5
Double-click the setting to open the Enter Integer Value window.
Step 6
Type "0" and click "OK" to set the value to zero. Firefox scripts now run indefinitely, and will not throw any script errors.
Step 7
Restart Mozilla Firefox.
Excellent solution in this question: How can I give control back (briefly) to the browser during intensive JavaScript processing?, by using the Async jQuery Plugin. I had a similar problem and solved it by changing my $.each for $.eachAsync
there could be an infinite loop somewhere in the code
start by commenting out codes to identify which section is causing it
too many loops: there might be a chance that your counter variable name clashes, causing the variable to keep resetting, causing the infinite loop.
try as much as possible to create hashes for your objects so much so that read time is O(1) and in a way caching those data
avoid using js libs as some of the methods might cause overheads. eg. .htm() vs .innerHTML
setTimeout() yes and no -- depends on how you chunkify your codes

Categories