I've got a simple timer that I built that works off of a setInterval function. Every 1 second, it increases the value of the timer by 1. When I click off of the tab to a different tab in Safari, it slows down. You can see what I'm talking about in this basic CodePen:
http://codepen.io/anon/pen/rxVMRp
This is the basic JS code:
function setTimer(){
var curTime = parseInt($('.timer').text());
var newTime = curTime+1;
$('.timer').text(newTime);
}
setInterval(setTimer, 1000);
Granted, my timer is a bit more advanced, but you can still see the slow down effect of setInterval in Safari in this basic example. How can I prevent this slow down without having to offload anything to a web worker?
Is there any particular reason you're using a setInterval here? Probably the reason Safari is slowing down on blur is to prevent tabs from wasting CPU cycles when the user isn't paying attention to them. What could possibly be so important in your code that it needs to be updated every second, even when the user isn't focused on it?
At any rate, you could listen for onblur and onfocus to pause or restart the timer as necessary. If you need to keep perfect timekeeping for some other purpose there is always Date.now().
Related
Is it possible to run a timer in the background (in both iOS and Android) or will it be out of the app-guidelines (specifially on iOS). Right now I am having a meditation-timer-app and one of the most important things is that the time should keep on running while in background mode (if the phone display is black or the home screen is opened).
I am using an interval setInterval() - Method of 1000s to count down each second.
https://capacitorjs.com/docs/v2/apis/background-task#background-tasks says it may not be possible:
NOTE: On iOS setTimeout and setInterval won’t work once your app is in background, so don’t use them inside beforeExit.
So another idea that I would have would be to make a calendar event (for example for a Date that is 10 min in the future if you set the timer to 10mins).
Than it would be a scheduled timer event. If you reopen the app, the timer gets adapted to the calendar event.
Is this possible to wait for a specific date to happen? And how?
Do you have a better solution or can I just use the interval in the background somehow?
For my app this would be very important, since when meditating, you don't want to have the phone open. You want to start the timer and put the phone away.
We are using setInterval & setTimeout both tried in our demo for a time interval. When on safari we will minimize the screen these two methods pause and not working. so, we will get a value mismatch in windows chrome and mac safari.
Anyone can help with it?
Thanks!
Chrome will suspend or slow down timers in some situations as well, I'd be surprised if Firefox doesn't. You can't control how the browser de-prioritizes your window/tab when it's not active.
It's never a good idea to rely on the timer interval, whether setTimeout or setInterval. Any number of things can delay the timer callback, making it happen later than you asked.
If the exact amount of time that passed is important, remember when you started the timer (const start = Date.now();) and find out how long it's really been when the timer callback is called (const elapsed = Date.now() - start;) and act accordingly.
I've got a page that shows real-time statistics. It runs a lot of javascript, makes a lot of HTTP requests, renders SVG charts every few seconds using D3.js, has a lot of CSS animations, and rearranges the DOM frequently.
As long as the page is focused, it runs smoothly. If I switch to another tab and come back later, there's often a short pause where the page seems to be frozen before the view suddenly seems to rerender and the page becomes usable again. The longer the tab has been backgrounded, the longer this pause is. If the tab has been in the background for a very long time (hours) and I switch back to it, it will be frozen for a long time then crash.
All these behaviors are observed in Chrome. I haven't tested much in other browsers.
What is Chrome doing during that pause when I first switch back to the tab?
You're running a setInterval or a series of setTimeouts.
Each one is queued up to run AFTER the point you specify in the function.
Google throttles everything on your page down to a few updates every second...
...so if you've got timers set to move things around and animate at 30fps or whatever, then you've got Google firing one round of updates (whatever you have scheduled), which will undoubtedly call something requesting another update, which will request another one...
...when you switch back, you've got hundreds (or tens of thousands) of these updates waiting to happen, and now instead of happening at 30fps, you have a bunch of these things waiting... all of them have passed their "do not run until..." time, and they're all going to try to update as fast as physically possible, until you get caught up to where the timer is current again.
If the browser supports the components of the page-visibility API, then pause your calls when the page is not visible.
if (!document.hidden) { doStuff(); }
OR
document.addEventListener("visibilitychange", function (evt) {
if (evt.visibilityState === "hidden") { myApp.pause(); }
else if (evt.visibilityState === "visible") { myApp.resume(); }
});
If it doesn't support the API, then you can try to polyfill it, using window.onblur, or otherwise.
That said, chances are if the browser doesn't support the page-visibility API, it also doesn't do hardcore throttling of the page-code.
That's not a 100% guarantee, but rather a semi-likelihood.
So I have this weird issue that i am hitting, i have a slide show in which set interval fires up jquery animate method. all works great.
Until i switch tabs. If i switch back to tab with slideshow in some time, all of the sudden animation is fired repeatedly, with out any inteval in place. Like it is playing catch up.
I kind of figured that it has something to do with RequestAnimationFrame and jQuery's animate method. And how animation rendering is suppressed while tab is inactive. While interval is kept on firing up every so often, even when window is inactive.
Could any one elaborate more on this, would much appreciate it.
Here is the core code that does that:
function animate(setCurrent){
animationDistance = opt.cSlideWidth * (opt.cCurrentSlide - 1);
carousel.animate({left: '-' + animationDistance}, opt.cTransitionSpeed});
}
opt.cSetUpIntervalMethod = function(action){
if (action === 'start') {
clearInterval(opt.cSlideTimer);
opt.cSlideTimer = setInterval(function(){animate();},opt.cSlideDelay);
}
}
opt.cSetUpIntervalMethod('start');
This was a bug in older versions of JQuery which has since been fixed as of 1.6.3. Update your version.
"We had high hopes for the browser’s requestAnimationFrame API when we
added support into version 1.6. However, one of the highest-volume
complaints we’ve received since then relates to the way
requestAnimationFrame acts when a tab is not visible. All the
animations initiated when the tab is invisible “stack” and are not
executed until the tab is brought back into focus. Then they all
animate at warp speed! We’ve removed support for this API (which has
no impact on the way you call jQuery’s animation features) and plan to
incorporate it into a future version of jQuery."
http://blog.jquery.com/2011/09/01/jquery-1-6-3-released/
Chrome and Firefox slow down interval timers when a page goes to the background to preserve CPU and battery. When you bring it back to the foreground, they try to "make up" for some of the lost timers. See this post in the Chromium blog for a brief description of what they implemented.
The best way to solve the issue is to stop your animation when your window goes out of view and start it again when it comes back into view.
Chrome has an experimental API for doing just this. If that is not available, fallback methods involve using focus detection to see if focus is anywhere in your window.
do not use setinterval() for animations that can lose focus. you accomplish the same effect with .delay(milliseconds) and a recursive javascript method call.
It may be a naive question but I need to know the answer.
This is my code,
setInterval(function() { /do stth./}, 1000);
I never cancel the timer, I need to run it as long as user is on the page, I need to know will it case any memory leak, or when will it stop (ie, browser refresh, browser close)?
The only problem can occur when you "do something". If you have other long running functions or even additional intervals inside the interval (a la Javascript Inception) then you could run into performace issues.
However, in almost all cases, you won't have any problems.
When the user refreshes the browser, the interval will begin anew. When the browser is closed then all activity stops.
As long as the user doesn't refresh the browser or leave the page then the interval will never end.
it stops when you leave the page. It shouldn't cause leaks.