72

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.

Kara
  • 6,115
  • 16
  • 50
  • 57
JeanPaul
  • 721
  • 1
  • 5
  • 3
  • 7
    Since you are using Firebug, try to add console.log's to your code to see how far it will run. I've found the source of many issues like this before. – T. Junghans Sep 07 '11 at 06:26

13 Answers13

38

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.

Jose Faeti
  • 12,126
  • 5
  • 38
  • 52
  • 1
    Can you confirm that this works reliably in all major browsers? Plausibly, a browser's console.log implementation might wait until after executing any queued Javascript before updating the visible content of the console - leading to the illusion that an infinite loop occurred earlier than it really did. I don't actually know of any browsers where this method will fail and be deceptive in that way, but then, I haven't tested; some hard facts with evidence on whether or not such traps exist would enhance this answer. – Mark Amery Apr 09 '13 at 13:27
  • 1
    You may be right, some browsers (especially young ones) may behave in a different and unpredictable way, but then you should create your own plugin for debugging purposes, one which can wrap the debug.log function so that you can adjust it to solve these issues. – Jose Faeti Apr 10 '13 at 08:23
  • 1
    For example my log function calls both debug.log (if present in the current browser), and updates a log in a debug element of the page, created by my plugin, which can either append a message or send an ajax request to a remote debugger which will record the messages in one or more log files. Don't rely uniquely on browser features, abstract them so that you can obtain the same functionalities on all browsers. – Jose Faeti Apr 10 '13 at 08:23
  • This solution will just freeze the browser (it freezes current Chrome, even though Canary seems to be able to take it); what you do is just `throw "debug 1";` and the script execution will stop there; or comment code out. – srcspider Aug 01 '13 at 07:18
  • I forgot to mention, make sure you're running vanilla version of the browser so absolutely NO extensions. :) – srcspider Aug 01 '13 at 07:31
  • 1
    @srcspider I put the while loop in there to show you can still access the console even if the current page hangs... the point is printing useful debug messages in absence of a proper debugger. You could also send an ajax request to your server and fill an error log there instead of using the browser's console. – Jose Faeti Aug 01 '13 at 08:16
  • How is this approach *not* commenting the hell out of your code? – Michael Nov 24 '15 at 18:36
  • @Michael the point with logging is to be able to see the program flow outside the program (for example in a text file), so that you can analyse the program behaviour after an error. You are not commenting out any code, or changing the behaviour of the code in any way (logging shouldn't be something which causes the program to behave differently if present). Once you have a logging mechanism in place, you can pass different loggers depending on your needs, just from a config parameter. For example different loggers for development and production, or for text files or external displays, etc. – Jose Faeti Nov 25 '15 at 08:58
24

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.

Christopher Reid
  • 4,318
  • 3
  • 35
  • 74
  • Putting console logs varies the environment as it takes time and cpu to processes and display. That being said it you don't mind leaving them in after the code goes live it will work. – Fi Horan Aug 08 '16 at 15:32
  • You can achieve the same behaviour by inspecting > Sources > find the suspicious location or file > simply click on the line number (This will add a debugger on the fly), incase someone is working with code they have not yet checked out, or reloading is expensive operation. Then once caught in debugger, you can take benefit of the watchlist (for variables, arguments etc) and step over resume functions – Harsh Phoujdar May 19 '22 at 09:18
20

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

Ricardo Tomasi
  • 34,573
  • 2
  • 55
  • 66
  • 2
    Note that the dev tools typically (always?) have to already be open for the `debugger` breakpoint to be hit; the command is transparent (just like `console.log`) during normal operation. This makes sense, because you wouldn't want an overlooked debugging command in a user's browser to halt execution and open the dev tools window; a bad experience at best, and possibly panic inducing for non-techy people. "Oh no! Visible code means this site is hacking my computer!" – brichins Mar 23 '17 at 17:11
8

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 ...

kxr
  • 4,841
  • 1
  • 49
  • 32
  • 1
    Yeah, it works at any time... except when Firefox says the web page is slowing down your browser because it's in an endless loop... which is exactly when you need it. – Andrew Jan 29 '20 at 18:33
7

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.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • 4
    This isn't a *bad* answer... but there's nothing about it specific to this question. Nothing about the browser; nothing about JavaScript... this is more fundamentals of debugging than specific advice on a specific situation. – Richard JP Le Guen Sep 06 '11 at 15:16
  • 1
    @Richard JP Le Guen, can you see a specific situation in the question? I can't thus the general answer. – Darin Dimitrov Sep 06 '11 at 15:44
  • 1
    @Darin Dimitrov - The above listed JavaScript and browser :P The asker even mentions Firebug, reinforcing my perception that they're fishing for profiling tools which they can use to debug the browse crash. (but I don't know any :( ) – Richard JP Le Guen Sep 06 '11 at 16:35
  • 1
    -1 Really a bad JavaScript debugging technique. We have logs to track down program flow. No need to comment or remove parts of code, especially when you have a complex web application which may need to use all that code. – Jose Faeti Sep 12 '11 at 12:07
  • @Jose Faeti, this technique has always worked perfectly fine for me. That's why I posted it. Of course the question here is subjective, so you can only expect to find subjective answers here. As you can see while this technique works for some, it might not work for others. So you cannot expect an objective answer to a subjective question. – Darin Dimitrov Sep 12 '11 at 12:10
  • @Darin It could be subjective, but what's better for you? commenting out the code one by one, then having to remove comments, or have a log following the program flow? Just like Unit Tests, log are a powerful debugging feature that should be written as soon as you write your main code. Given the high flexibility of JS, you can create an external library to implement log to your functions, objects, etc. you will only include when you want debugging (i.e development), and not include it when you don't need debugging (i.e production). – Jose Faeti Sep 12 '11 at 12:14
  • @Jose Faeti, did I ever mentioned something about logging in my answer? Why are you left with the impression that I am against using logs and tracing? It's just that when you are debugging a javascript that hangs, that's probably due to some infinite recursion or very poor code, so while logging in this case might be useful, trying to narrow down the location of the problem is more important. – Darin Dimitrov Sep 12 '11 at 12:16
  • @Darin agree 100% with that, but: "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." and "How can I narrow down where the problem is?". He doesn't have the pale idea of where the error may be, with a system to track program flow he will be able to see where the code hangs, without blindly remove parts of code. – Jose Faeti Sep 12 '11 at 12:18
  • 1
    @Jose Faeti, it's exactly because he doesn't have the pale idea of where the error may be that the first thing to do is to try to narrow it down. – Darin Dimitrov Sep 12 '11 at 12:31
4

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! ;)

Totty.js
  • 15,563
  • 31
  • 103
  • 175
  • 2
    +1 Note that you can click on the "pause" button to stop the script at the point where it is right now. The great thing here is that you can do this while the page "hangs", i.e. eats 100% since it hangs somewhere in JavaScript. – Aaron Digulla Apr 12 '14 at 20:57
  • Exactly, that answer is so old! hehe so many changes, yet I'm still with Google chrome! – Totty.js Apr 13 '14 at 19:00
  • 8
    Unfortunately the reason I found this page is because I have some javascript that locks up Google Chrome to the point that F12 does nothing. – Jeremy List May 20 '15 at 00:56
  • 1
    When I have the debugger running in a separate window before I load the page, and it's already on the Sources tab, I can click pause even after the browser is hanging. – Glen Pierce May 26 '16 at 00:43
2

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>
Trevor
  • 13,085
  • 13
  • 76
  • 99
  • 5
    Alerts are ideal when trying to find what call from a stack results in the browser hanging, because alerts stop all execution of javascript until you click ok. If you use console.log instead, the browser will still crash and you may not see the logs. – Benno Sep 13 '11 at 08:24
  • 1
    @Benno: actually you will be able to see the console in Opera, FF and Chrome even if the browser hangs, if you display them as separate windows. – Jose Faeti Sep 13 '11 at 13:28
  • 1
    @Jose Faeti: Wouldn't it depend on where you log? If you happen to log INSIDE an infinite loop (not knowing that part was the loop), that is what will cause it to crash (too many logs to the console crash my browser...), whereas an alert will completely stop execution of the loop each time it goes through. – Benno Sep 14 '11 at 01:49
  • 2
    Alerts are good for a little website with a couple of small jQuery scripts. For a complex web application like the OP is using, you often have many asynchronous scripts and events, and big scripts. It's impossible to write alerts between the code just for debugging. You need a log system to track down your program flow, so when you run the application you will look at it and see what is being called and what not. The point is planning ahead a logging system in every critical part of your application. – Jose Faeti Sep 14 '11 at 05:23
  • Evan in large scripts I prefer to use alerts. I realize logging isn't much of a performance hit, but the larger the script the bigger the hit and it dirties the code. Plus, it's usually not hard to narrow down the area of code that's having the problem (e.g. I know it doesn't crash until after I hit this certain button). Even if you had to use a binary search to find the trouble code, that wouldn't take very long. I know people are going to think I'm crazy for hardly ever using a logging system, even in a large application, but I think those should be used more sparingly than they are. – Trevor Jan 18 '13 at 18:05
1

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

Manfred Radlwimmer
  • 13,257
  • 13
  • 53
  • 62
Ihab Salem
  • 83
  • 5
1

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);
});
Markus
  • 3,225
  • 6
  • 35
  • 47
1

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.

dougajmcdonald
  • 19,231
  • 12
  • 56
  • 89
0

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.

Lathejockey81
  • 1,198
  • 7
  • 8
-1

I ran into same problem and that's how I resolved it.

  1. Check Console for errors and fix them

Some time console even is hanging

  1. Check for all the loops if the one is infinite
  2. Check for recursive code
  3. Check for the code which is dynamically adding elements to document
  4. Use break points in your console
  5. Use some console logging i.e log the suspected code blocks
Tofeeq
  • 2,523
  • 1
  • 23
  • 20
  • All the recursive errors I've had before will break pretty quickly because all implementations of JavaScript have a relatively small stack. Each function call adds one, each return decrements by one. If the counter goes over a certain number (maybe 1,000) then you get an error, not an infinite loop. – Alexis Wilke Nov 27 '18 at 07:28
-2

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

Andrew
  • 5,839
  • 1
  • 51
  • 72