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.
Related
So I have this vanilla JavaScript code that is running very slow when on certain older mobile devices (like iPhone 5) but runs flawless on newer devices (like iPhone 7). And I'm not talking about load speed, but the actual JavaScript functionality. I'm using a few addEventListener to handle basic stuff like showing and hiding divs, including an overlay div with transparent opacity. When I click the button which has the addEventListener linked to it, it takes sometimes up to two seconds to show and/or hide the divs. Sometimes it won't even do it and I'll have to click the button again. I won't share the entire JS file here, but I can assure it's pretty basic. What I want to know is if there's someway to track the execution speed of the JavaScript code... Like, I'm not sure if it's something in the actual JS code, or it's slow because the brownser is taking a long time to rendering it. Any help is welcome! =)
2 ways that are available:
The developer tools in Chrome, but Firefox is more useful for tracking performance:
Also, try performance.now(), never used it but heard about it. Maybe that will help.
EDIT: You could also check how it runs via breakpointing. You can breakpoint in Chrome and Firefox I believe.
I have the following code, it fades elements in and out in a repeating cycle. When the tab is inactive the text within the divs piles up on top of each other for a split second before being cleared when the tab is activated again. Is there a way to stop this animation when the window blurs and start it again on focus?
(cycle = function () {
setTimeout(function(){$('#right').fadeOut(1000)},10000);
setTimeout(function(){$('right').fadeIn(1000)}, 11000);
setTimeout(function(){$('#left').fadeOut(1000)},13000);
setTimeout(function(){$('#left').fadeIn(1000)},14000);
setTimeout(function(){$('#left').fadeOut(1000)},15000);
setTimeout(function(){$('#left').fadeIn(1000)},17000);
})();
I gave a suggestion in a comment, but then remembered that that solution is not necessarily cross-browser compatible, as I had come across it before, thus the creation of my plugin.
Suffice it to say, $(window).blur() and focus do not always work as expected on all browsers. I don't remember the exact list of problems I ran into, but I know some were things like; clicking on another tab (in FF, i think) did not trigger the blur, clicking on another program would trigger the blur despite the fact my main browser window was still open and that tab had focus, it ddnt have Windows Focus, etc...
The following plugin I created might be helpful in that I've filed it down to work in "most" browsers and versions (not tested on all versions) and it functions exactly as we expect where I work. It only goes blur if the exact browser window's tab loses focus to another tab of the same browser. And of course vice versa with focus.
See jsFiddle Example usage and unminified code
Minified Plugin:
Simply Add to a js file to be called after jquery or place at top of your code
(function(jQuery){jQuery.winFocus||(jQuery.extend({winFocus:function(b){function c(a){a=a||window.event;a.hidden=a.type in{focus:"visible",focusin:"visible",pageshow:"visible",blur:"hidden",focusout:"hidden",pagehide:"hidden"}?"focusout"===a.type:this[d];jQuery(window).data("visible",!a.hidden);jQuery.winFocus.methods.exeCB(a)}var d="hidden";d in document?document.addEventListener("visibilitychange",c):(d="mozHidden")in document?document.addEventListener("mozvisibilitychange",c):(d="webkitHidden")in document?
document.addEventListener("webkitvisibilitychange",c):(d="msHidden")in document?document.addEventListener("msvisibilitychange",c):"onfocusin"in document?document.onfocusin=document.onfocusout=c:window.onpageshow=window.onpagehide=window.onfocus=window.onblur=c;for(x in arguments)"object"==typeof arguments[x]?(arguments[x].blur&&(jQuery.winFocus.methods.blur=arguments[x].blur),arguments[x].focus&&(jQuery.winFocus.methods.focus=arguments[x].focus),arguments[x].blurFocus&&(jQuery.winFocus.methods.blurFocus=
arguments[x].focus)):"function"==typeof arguments[x]&&(void 0===jQuery.winFocus.methods.blurFocus?jQuery.winFocus.methods.blurFocus=arguments[x]:(jQuery.winFocus.methods.blur=jQuery.winFocus.methods.blurFocus,jQuery.winFocus.methods.blurFocus=void 0,jQuery.winFocus.methods.focus=arguments[x]))}}),jQuery.winFocus.methods={blurFocus:void 0,blur:void 0,focus:void 0,exeCB:function(b){jQuery.winFocus.methods.blurFocus?jQuery.winFocus.methods.blurFocus(b,!b.hidden):b.hidden?jQuery.winFocus.methods.blur&&
jQuery.winFocus.methods.blur(b):jQuery.winFocus.methods.focus&&jQuery.winFocus.methods.focus(b)}})})(jQuery);
Also: #line-o 's referenced SO Question is where I was first inspired to write this plugin and I also have this plugin answer posted there. lol
Take a look at the Visibility API for current browser. You'll still need a fallback for older ones (namely IEs).
Or you might find a solution here:
Is there a way to detect if a browser window is not currently active?
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.
I'm trying to get add a delay of 1000ms before a person leaved the page. I'm using the beforeunload event to start a jquery animation and would like it to finish before the page leaves.
I'm not concerned with older browsers, IE9, latest safari, chrome and FF4 are all i'm interested in.
Edit: Well I was hoping to implement it when just navigating internal pages. Sure I can make all my internal links a javascript call, but I would have preferred a less brute force method.
Also, I'm not stopping people from leaving the page, not even making them wait a huge long time, 1 second for a fade out? Thats no worse than every game I play fading out when I select quit.
Now had I asked how do I prevent a person from leaving a page, then yes all the "don't do it" would have been deserved.
Firstly, if people want to leave your page, don't put any barriers or difficulties in leaving it. Just let them.
Konerak said it well...
Using a blocking action is acceptable when the user is about to lose data by leaving the page, but using them for animations and gimmicks will quickly annoy your users.
Secondly, you can only prevent automatic closing with a blocking action, such as an alert() or prompt(), which temporary blocks the browser's viewport, waiting for user response.
jsFiddle.
Well I was hoping to implement it when just navigating internal pages.
I know it’s four years later now, but I wanted to point out that, within the bounds you’ve described, you can do this.
$(document).on("click", "a", function (e) {// Listen for all link click events on the page (assuming other scripts don’t stop them from bubbling all the way up)
// Stop the link from being followed.
e.preventDefault();
// Grab the link element that was clicked
var linkClicked = e.target;
// I'm using setTimeout to just delay things here, but you would do your animation and then call a function like this when it’s done
window.setTimeout(function () {
// Simulate navigation
window.location = linkClicked.href;
}, 1000);
return false;
});
It’s still inadvisable:
I suspect it would get annoying to users pretty quickly
Without additional code, this would prevent users from command/control-clicking to open links in a new tab.
8 years later and I'm about to code this for my own website, specifically as a fade between pages. But I'm only going to do this for navigating between pages within my site, and I'm not going to use window.onbeforeunload or window.onclick. I attach a click event handler to specific "buttons" on each page. pointer-events is even disabled for other elements, so the event's element scope is very limited. The code is a switch() statement with cases for each "button". Each button navigates to a specific page within the site.
I don't think this is bad web page or web site behavior. A 1 second delay when transitioning between pages is not going to annoy users. I think you might be able to get 2 seconds or more out of it, if you include the time it takes to load the destination page, which can also fade in gradually in as it loads data.
It's visually elegant, especially compared to typical news/info sites with flex layouts that shift all over the page while they load. Those pages spend 2 or more seconds shifting stuff around before you can read anything.
My site is already filled with CSS and SVG animations, so adding this to the internal page navigation is no sweat for this project. If you limit the element scope of the user events and you make the delays small, this is good behavior, not bad behavior, IMO. Visual elegance has value.
EDIT- As I get into it, I see that for one group of similar pages I can achieve better cross-fading between them by consolidating them into one page. That way I can truly cross-fade between each sub-page instead of fading out one page then fading in another.
I observe this behaviour currently in Firefox 3.6.12:
When I start loading a page and then switch while it is still loading to another tab or window and come back when loading is finished, the "dom:loaded" event has not been triggered by the document observer.
Any ideas how to solve this?
It sounds like a bug in Firefox, you should report it to Mozilla. You could also try reporting it to the Prototype mailing list and they might find a solution for their next version. Both of these means waiting for a fix that might not come. But you should still report it as a bug for everyone's benefit.
You could simply move your script to the very bottom of the page, although it will run sooner than "dom:loaded" the relevant parts of the DOM should be instantiated by then.
Or you could observe the body's onLoad event, that will run later (after images are loaded) so is safer.