I'm dealing with a difficult bug where a setInterval callback only gets called 20 or 21 times and then never again, even though I never cleared the interval. (running in Chrome at least)
The page remains responsive, so the callback is not getting stuck in an infinite loop.
Do browsers decide to stop calling a setInterval callback if it takes too long to execute? For instance if some expensive canvas drawing is performed in the setInterval callback?
Unfortunately there are too many potentially-involved layers in this issue (i.e. React, Redux, custom Redux middleware, Canvas drawing) to post a good code sample here. I am asking about the expected behavior of setInterval in modern browsers.
EDIT I think I may be seeing a bug in Chrome to do with canvas drawing inside of setInterval/setTimeout. I can't reproduce in Firefox.
Judging by the setInterval documentation, the only mention of "variation" from the standard behavior seems to be:
Starting in Gecko 5.0 (Firefox 5.0 / Thunderbird 5.0 / SeaMonkey 2.2), intervals are clamped to fire no more often than once per second in inactive tabs.
Related
I'm currently developing a mobile single page webapp using React and Nuclear.js with Immutable.js.
When I due with click event, there's always a delay about 200ms long. I thought it was because the "click delay" problem, so I changed to touch events, which is onTouchStart in React.
But the delay seems still there. I use timeline view in devtools to investigate the delay, found the time was cost in "native v8natives.js:1229", as shown below:
I'm wondering what is the delay? and why it is always there, even when I use touch events instead of click.
I investigated it further today. The time shown in the chart is not that accurate and kind of misleading.
In fact, the time of the execution is included in that delay, though it is not shown.
So after digged into my scripts, using console.time() and performance tools packaged with React, the delay now is decreased dramatically.
I noticed this strange behaviour with the latest iOS (iOS 6). If calling a function for any touch event which has a setTimeout inside, the part inside the setTimeout is never triggered.
This happens only when there is a "system animation" such as scroll and zoom-in/out.
For example:
http://jsfiddle.net/p4SdL/2/
(I used jquery just for testing but the same happens with pure js)
Open that page with safari on any iOS 6 device and zoom in or out. The alert will never be called.
If tested on any iOS 5 device this will work just fine! It seems that during these animations the setTimeout or setInterval are reset by the OS. Is this the intended behaviour or a bug?
Thanks
Note: It looks like UIWebView does not support requestAnimationFrames. Thanks to Guillaume Gendre for pointing it out!
We ran into a similar issue with a web app we're working on.
For us, it was touchmove that caused issues. We implemented a workaround (found here: https://gist.github.com/3755461) that seemed to work pretty well until another issue forced us to abandon it. (I tried adding the workaround to your fiddle and was able to get the timer to fire once or twice, but it required a weird gesture+scroll event that was damn near impossible to consistently reproduce.)
Anyway, one of the new features in iOS 6 for developers are requestAnimationFrames. My workaround is basically a wrapper for timers, allowing the developer to pass a boolean, which will call either the native function or the workaround function.
For example:
setTimeout(function(){alert("HI")}, 1000); // using native
setTimeout(function(){alert("HI")}, 1000, true); // using workaround
Here are additional ways to use the workaround:
setInterval(function(){console.log("Interval")}, 1000, true);
var timer = setTimeout(function(){ /* ... */ }, 60000, true);
clearTimeout(timer);
var interval = setInterval(someFunc, 10000, true);
if(someCondition) clearInterval(interval);
Here are two fiddles with the workaround examples. Try pinch/zooming on the black squares:
http://jsfiddle.net/xKh5m/embedded/result (Uses native setTimeout function)
http://jsfiddle.net/ujxE3/embedded/result
We've been using this workaround for a few months in a production environment, and have not run into any major issues.
Here's a public gist of the workaround: https://gist.github.com/4180482
Here's more information about requestAnimationFrames:
MDN documentation
Paul Irish on requestAnimationFrame
Good luck!
A few questions here:
Is there anyway to keep iOS from freezing javascript on the page while scrolling?
Does iOS freeze javascript when your in another tab or if you switch apps?
Are there any other major javascript limitations on iOS?
iOS 6.x suspends all event timers in response to touch events like scrolling and has a tendency not to start up all the timers again once the event is done. It's a well known iOS 6 bug that is super-annoying. It pretty much breaks parallax and stuff. Some people have resorted to building their own scroll functionality.
Here's another StackOverflow on the same topic:
iOS 6 safari, setInterval doesn't get fired
and another:
setInterval pauses in iphone/ipad (mobile Safari) during scrolling
and here is the closest thing you'll get to a bug report on it (Apple doesn't make bug reports public to maintain the illusion of perfection, so developers made their own bug site): http://openradar.appspot.com/12756410
This bit of code will unfreeze timers that are broken / lost / destroyed by iOS during a page scroll: https://gist.github.com/ronkorving/3755461
This is another attempt to fix the freeze: iOS 6 js events function not called if has setTimeout in it
Unfortunately, there is nothing you can do to fire events WHILE page scrolling. Like fade out a back-to-top link when scrolling up the page. When it comes to scrolling, iOS6 is incapable of rubbing it's tummy and patting it's head. (iOS5 works fine, btw. This is a regression)
To answer the third question, a decent-sized limitation is that sometimes innerHTML just plain doesn't work. From the accepted answer:
It happens when the CPU of the phone is very busy (say 100%). Then the rendering engine sometimes forget about innerHTML settings.
The solution included in my unify project is to test if there is an element in childNodes, otherwise apply it again.
I am using the latest version of jqGrid (4.x) for an application displaying local data.
Win7: All works fine on several browsers (Chrome, FF, IE, Safari).
In iPad's Safari the grid works excellent, but there is one issue:
When I unload the grid because I need to redefine its columns, this either takes extremely long or times out. I am using purely local objects - no back-end connectivity involved. Debug console on iPad Safari: JavaScript execution exceeded timeout
I have tried both ways:
$("#myGrid").GridUnload();
$("#myGrid").GridUnload("#myGrid");
I can reproduce the issue, when I skip the GridUnload part the issue is gone. As said above, on a Win7 Safari this is not problem at all.
Any ideas how I could work around the issue?
-- UPDATE ---
This issue was very hard to trace for me, since I am not aware of how to debug JS code on an iPad. So far, this issue seems not to be specific to jqGrid, but the timeout happens whenever something in JS takes to long. For some reasons I do not understand yet, this seems to be the GridUnload().
Can somebody tell me, whenever this Safari iPad Javascript timeout is happening, I have no idea what triggers it.
I'm currently working on a jQuery plugin that tracks a visitors mouse behavior. Movements, clicks, scrolling and resizing are all recorded and sent, via Ajax, to a location where this data is parsed and stored.
Originally, the data is sent to a script when the user leaves the page. By 'leaves' I'm referring to refreshing, going back and forth though history, closing the window/tab and going to a different address.
The solution works in all browsers EXCEPT for Opera. I'm using jQuery's 'unload' event which isn't supported by Opera at all. Neither is onbeforeunload or onunload.
The question is, how do I implement this kind of functionality for Opera browsers?
One solution I had was to make special use of a 'polling' feature I created. This feature allows you to specify an interval which pushes the content to the server every 'x' seconds. Setting this to 1 second specifically for Opera browsers would probably solve this issue, but it's an awful amount of overhead and the requests aren't always completed in sequence, etc ...
Any suggestions or am I only stuck with the above option?
Thanks!
I suppose I could just link you guys to the plugin source. http://www.thedrunkenepic.com/junk/jquery.mousalytics.js
Regarding the code linked above, adding:
if(window.opera)
{
options.interval = 1;
}
On line 89 works great. My only concern is overhead, so I'm still looking for a more elegant solution.
According to http://bytes.com/topic/javascript/insights/799229-browser-quirk-onload-onunload-do-not-fire-back-forward-refresh-opera, Opera never really fires onload / onunload events, so functionality like this isn't possible without hacks.
http://dev.opera.com/articles/view/efficient-javascript/?page=4 seems to confirm this, and basically states that opera tries to maintain the state of the page across requests.
On further investgation, http://unitehowto.com/Onunload indicates that it might be possible with opera.io.webserver.addEventListener('_close', onunload, false); (where onunload is a previously defined function), however it also indicates that this functionality is not consistent across all versions of opera, and might not work at all.
I think that your best option is probably to use the polling option for Opera, or possibly use a server-side check for the current page and where it falls in the history queue.
Does adding this line of JavaScript work for you?
history.navigationMode = 'compatible';
Source: http://www.opera.com/support/kb/view/827/
I've had the same problem and this saved my day:
if( typeof(opera) != 'undefined' )
{
opera.setOverrideHistoryNavigationMode( 'compatible' );
history.navigationMode = 'compatible';
}
More info about this problem can be found at: http://www.opera.com/support/kb/view/827/