Countdown Timer 'Delays' When Tab Is Inactive

Countdown timer 'delays' when tab is inactive?

For this you can use the HTML5 Visibility API for detecting if the browser tab is active or not. And use regular binding of event handlers for focus and blur for the browser window.

Basically you pause() the timeline when you blur out of the tab, and then play() when you give the tab refocus. Example of this in action:

http://codepen.io/jonathan/pen/sxgJl

// Set the name of the hidden property and the change event for visibility
var hidden, visibilityChange;
if (typeof document.hidden !== "undefined") { // Opera 12.10 and Firefox 18 and later support
hidden = "hidden";
visibilityChange = "visibilitychange";
} else if (typeof document.mozHidden !== "undefined") {
hidden = "mozHidden";
visibilityChange = "mozvisibilitychange";
} else if (typeof document.msHidden !== "undefined") {
hidden = "msHidden";
visibilityChange = "msvisibilitychange";
} else if (typeof document.webkitHidden !== "undefined") {
hidden = "webkitHidden";
visibilityChange = "webkitvisibilitychange";
}

// If the page is hidden, pause the video;
// if the page is shown, play the video
function handleVisibilityChange() {
if (document[hidden]) {
tl.pause();
} else {
tl.play();
}
}

// Warn if the browser doesn't support addEventListener or the Page Visibility API
if (typeof document.addEventListener === "undefined" || typeof document[hidden] === "undefined") {
// do nothing or throw error via alert()
alert("This demo requires a browser, such as Google Chrome or Firefox, that supports the Page Visibility API.");
} else {
// Handle page visibility change
// Pause timeline
tl.pause();
}

HTML5 Visibility Docs:

https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API

Regarding GreenSock Forum Topic:

http://forums.greensock.com/topic/9059-cross-browser-to-detect-tab-or-window-is-active-so-animations-stay-in-sync-using-html5-visibility-api/

Also in GSAP the equivalent for setTimeout() is delayedCall()

Provides a simple way to call a function after a set amount of time (or frames). You can optionally pass any number of parameters to the function too.

GSAP delayedCall(): http://greensock.com/docs/#/HTML5/GSAP/TweenMax/delayedCall/

//calls myFunction after 1 second and passes 2 parameters:
TweenMax.delayedCall(1, myFunction, ["param1", "param2"]);

function myFunction(param1, param2) {
//do stuff
}

I hope this helps!

Chrome: timeouts/interval suspended in background tabs?

I recently asked about this and it is behaviour by design. When a tab is inactive, only at a maximum of once per second the function is called. Here is the code change.

Perhaps this will help:
How can I make setInterval also work when a tab is inactive in Chrome?

TL;DR: use Web Workers.

How can I make setInterval also work when a tab is inactive in Chrome?

On most browsers inactive tabs have low priority execution and this can affect JavaScript timers.

If the values of your transition were calculated using real time elapsed between frames instead fixed increments on each interval, you not only workaround this issue but also can achieve a smother animation by using requestAnimationFrame as it can get up to 60fps if the processor isn't very busy.

Here's a vanilla JavaScript example of an animated property transition using requestAnimationFrame:

var target = document.querySelector('div#target')var startedAt, duration = 3000var domain = [-100, window.innerWidth]var range = domain[1] - domain[0]
function start() { startedAt = Date.now() updateTarget(0) requestAnimationFrame(update)}
function update() { let elapsedTime = Date.now() - startedAt
// playback is a value between 0 and 1 // being 0 the start of the animation and 1 its end let playback = elapsedTime / duration
updateTarget(playback) if (playback > 0 && playback < 1) { // Queue the next frame requestAnimationFrame(update) } else { // Wait for a while and restart the animation setTimeout(start, duration/10) }}
function updateTarget(playback) { // Uncomment the line below to reverse the animation // playback = 1 - playback
// Update the target properties based on the playback position let position = domain[0] + (playback * range) target.style.left = position + 'px' target.style.top = position + 'px' target.style.transform = 'scale(' + playback * 3 + ')'}
start()
body {  overflow: hidden;}
div { position: absolute; white-space: nowrap;}
<div id="target">...HERE WE GO</div>

How to create an accurate timer in javascript?

Why is it not accurate?

Because you are using setTimeout() or setInterval(). They cannot be trusted, there are no accuracy guarantees for them. They are allowed to lag arbitrarily, and they do not keep a constant pace but tend to drift (as you have observed).

How can I create an accurate timer?

Use the Date object instead to get the (millisecond-)accurate, current time. Then base your logic on the current time value, instead of counting how often your callback has been executed.

For a simple timer or clock, keep track of the time difference explicitly:

var start = Date.now();
setInterval(function() {
var delta = Date.now() - start; // milliseconds elapsed since start

output(Math.floor(delta / 1000)); // in seconds
// alternatively just show wall clock time:
output(new Date().toUTCString());
}, 1000); // update about every second

Now, that has the problem of possibly jumping values. When the interval lags a bit and executes your callback after 990, 1993, 2996, 3999, 5002 milliseconds, you will see the second count 0, 1, 2, 3, 5 (!). So it would be advisable to update more often, like about every 100ms, to avoid such jumps.

However, sometimes you really need a steady interval executing your callbacks without drifting. This requires a bit more advanced strategy (and code), though it pays out well (and registers less timeouts). Those are known as self-adjusting timers. Here the exact delay for each of the repeated timeouts is adapted to the actually elapsed time, compared to the expected intervals:

var interval = 1000; // ms
var expected = Date.now() + interval;
setTimeout(step, interval);
function step() {
var dt = Date.now() - expected; // the drift (positive for overshooting)
if (dt > interval) {
// something really bad happened. Maybe the browser (tab) was inactive?
// possibly special handling to avoid futile "catch up" run
}
… // do what is to be done

expected += interval;
setTimeout(step, Math.max(0, interval - dt)); // take into account drift
}


Related Topics



Leave a reply



Submit