What in JavaScript can cause browser crashes? - javascript

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/

Related

Devtools analyse function calls and variables post-factum

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.

Why is Alert working as a pause?

First of all, apologies if this question was answered before.
I'm writing a code in JS to read an Excel File, get the value of the first cell in the column, search for it (it's an ISBN code, which I'm searching with the Google Books API) and get other relevant info, made available through the search (like Title, Subtitle and Author), then proceed to the next line and repeat the process.
My problem is writing the new data back in the Excel File. The code is writing all info in the last used row in the file. While using window.alert to flag the code, I noticed that when the alert was in a for loop, right before the search was initiated, the new data was inserted just fine, but if I tried to use a pause (like a timer function or a while loop to consume time) it didn't help at all.
What I want to know is why that behavior might be happening and, if possible, of course, a possible solution for my problem, since having to use alert as a pause isn't exactly the most interesting solution.
Thanks in advance
Alert will always stop all execution of code, except for web workers. Therefore, If you need to continue execution, use a web worker. Have a look at this for reference (the note part covers this topic partially)
When browsers show a native modal interaction widget, such as an alert, it transitions into a state that waits for the response. In this state, it is allowed to redraw the page and process certain low level events. Here's the code from Mozilla Firefox that alert() and confirm() use:
http://mxr.mozilla.org/mozilla-central/source/toolkit/components/prompts/src/nsPrompter.js#434
This openRemotePrompt function doesn't return until the user clicks "OK" on the alert. However browser behaves differently while the alert is open. A loop repeatedly calls thread.processNextEvent to do certain kinds of work until the dialog is closed. (It doesn't run the application's JavaScript code, since that's meant to be single-threaded.)
When you use a pure JavaScript busy wait, for example, by looping until a certain wall time, the browser doesn't take these measures to keep things moving. Most noticeably, the UI won't redraw while the JavaScript code is looping.

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's get-it-done nature

Is JavaScript intended to be running as little as possible on a website/webapp? By that I mean is the usual intention to run through all your js files as soon as the page loads and put them aside, and then when functions come up to execute them right away and be done with it?
I'm working on a project using google maps and I have a custom marker object scripted out, and a debugger has told me that the browser runs through all my js files before anything even appears on the page.
My problem comes in here: I wanted to animate certain markers to bounce up and down continuously with jQuery (similar to OS X icons in the dock) and my several attempts at infinite loop functions all just crash the browser. So I understand that the browser doesn't like that, but is there a way to have a simple script be repeating itself in the background while the user navigates the page? Or is JavaScript just not supposed to be used that way?
(I worked with Flash for a long time so my mindset is still there.)
Yes, Javascript functions should just do their bit and exit as soon as possible. The GUI and the scripts run on the same single thread, so as long as you are inside a Javascript function, nothing shows up in the browser. If you try to use an infinite loop, the browser will appear to freeze.
You use the window.setInterval and window.setTimeout methods to trigger code that runs at a specific time. By running an interval that updates something several times a second, you can create an animation.
You have to set a timer to execute a script after a defined time.
var timer = setTimeout(code, milliseconds);
will execute code in so-and-so milliseconds. Each execution of the script can set a new timer to execute the script again.
You can cancel a timed event using clearTimeout(timer).
Use setTimeout() or setInterval(). The MDC articles on it are pretty good.
You'll need to update inside of functions that run quickly, but get called many times, instead of updating inside of a loop.
Since you said that you are using jQuery, consider using its effects API (e.g., jQuery.animate()), it will make your life much easier!
Personally, I save as much code as possible for execution after the page has loaded, partly by putting all my <script>s at the bottom of <body>. This means a (perceived) reduction in page load time, whilst having all my JS ready to run when need be.
I wouldn't recommend going through everything you need to do at the beginning of the document. Instead, bind things to events such as clicks of buttons, etc.

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