Unresponsive Firefox Scripts and RUZEE.Borders
There are quite some complaints and solutions about Firefox displaying annoying “unresponsive JavaScript detected, continue?” messages.
If you have scripts that simply sometimes take longer to do their stuff, you shouldn’t however force your visitors to change the default JavaScript “timeout” value as proposed by the tips linked above. You should consider doing parts of your calculations asynchronously and give free the one and only JavaScript execution thread for some milliseconds. Firefox will be happy in this case and won’t display the annoying message anymore, even when configured with its default settings.
I did that with the latest version 0.12 of RUZEE.Borders. Let’s have a look at the main rendering loop:
render:function(onfinished){
if(onfinished) RUZEE.Borders.onfinished=onfinished;
var start=new Date().getTime();
for(rule in RUZEE.Borders.mappings){
var e=RUZEE.Borders.cssQuery(rule);
var b=new RUZEE.Borders.Border(RUZEE.Borders.mappings[rule]);
delete RUZEE.Borders.mappings[rule];
b.calc(e);
// if we are rendering for more than 3 seconds, give Firefox some time to get
// rid of the "unresponsive script" message.
if(new Date().getTime()-start>3000){
setTimeout('RUZEE.Borders.render()',0);
return;
}
}
RUZEE.Borders.renderCalcs();
if(RUZEE.Borders.onfinished) RUZEE.Borders.onfinished();
}
In the beginning, the script saves the current time. Then it iterates over all rules inside the mappings hash table. It removes each rule on calculation (b.calc(e) and the delete before that line). Nothing really exciting up to that point. But hey, now comes the trick: Inside the loop the time is checked how long the loop is already running. If that is more than three seconds, the loop will hibernate and schedule it’s executing after 0 seconds - so most probably right after the return statement.
Firefox sees that a script was running for something like 3 seconds and doesn’t realize that the script continues afterwards. The trick works, because the mappings hash table gets emptied more and more with each iteration. Once we are done, i.e. all mappings have been processed, the calculations finally get rendered (renderCalcs()) and the onfinished callback gets called.
Wait… onfinished callback? Well, the render method won’t block until all mappings have been calculated. It will return after something like max. 3 seconds, the rest will be calculated “in the background” via the “setTimeout deamon”. That’s why you have to use a callback that gets invoked once the calculations and renderings are finished - you can’t rely on the return of render anymore! Have a look at the “Internet Explorer Blank Page trick” in the Tips and Tricks section of the RUZEE.Borders page.
The method described here can be used for every “iteration takes too long in Firefox” problem - although the solution feels like Windows 3.0 programming, it’s kind of clean - hope you like it ;-).
Hi, the name's Steffen and I'm writing about the Web, programming
and all those things coming to my mind. Enjoy your stay.
August 15th, 2007 at 23:02
“setTimeout daemon” — I love it
So how did you determine “RUZEE.Borders.render()” was the code to place within setTimeout? Or, does it not matter?
What happens if the script gets to:
if(new Date().getTime()-start>3000){
…But 3 seconds haven’t passed yet?
January 14th, 2008 at 17:46
I am running Fedora 8 Linux and am using mozilla firefox 2.0.0.10. Every time I am on AOL’s Email page, i keep getting non-stop Unresponsive Script messages. It is so annoying but until I get a windows machine, I have to do with linux only. I keep the web page open 24/7 and that message has to stop.
March 19th, 2008 at 18:14
You saved my life!!! (OK, I’m exaggerating
I’ve been trying for about 3 hours to figure out how to get Firefox to update the display (for a custom progress bar) while a long script is running, and also to avoid the warning on slower computers. I knew about the setTimeout trick, but the problem is that Firefox doesn’t stop the page loading animation from spinning, and sometimes the green progress indicator in the status bar doesn’t finish either, even though the script has finished. The solution was to set the timeout value to ZERO milliseconds as you did in your script (I was using 10, 100+ ms values).
THANK YOU!
Kimberly: You can change the amount of time Firefox waits before showing the message — see http://kb.mozillazine.org/Unresponsive_Script_Warning
Leave a Reply