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

  1. Home
  2. javascript
  3. How can I make setInterval also work when a tab is inactive in Chrome?

I have a setInterval running a piece of code 30 times a second. This works great, however when I select another tab (so that the tab with my code becomes inactive), the setInterval is set to an idle state for some reason.

I made this simplified test case (http://jsfiddle.net/7f6DX/3/):

var $div = $('div');
var a = 0;

setInterval(function() {
    a++;
    $div.css("left", a)
}, 1000 / 30);

If you run this code and then switch to another tab, wait a few seconds and go back, the animation continues at the point it was when you switched to the other tab. So the animation isn’t running 30 times a second in case the tab is inactive. This can be confirmed by counting the amount of times the setInterval function is called each second – this will not be 30 but just 1 or 2 if the tab is inactive.

I guess that this is done by design so as to improve performance, but is there any way to disable this behaviour? It is actually a disadvantage in my scenario.

First answer

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 = 3000
var 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>


For Background Tasks (non-UI related)

@UpTheCreek comment:

Fine for presentation issues, but still
there are some things that you need to keep running.

If you have background tasks that needs to be precisely executed at given intervals, you can use HTML5 Web Workers. Take a look at Möhre’s answer below for more details…

CSS vs JS “animations”

This problem and many others could be avoided by using CSS transitions/animations instead of JavaScript based animations which adds a considerable overhead. I’d recommend this jQuery plugin that let’s you take benefit from CSS transitions just like the animate() methods.

Second answer

There is a solution to use Web Workers (as mentioned before), because they run in separate process and are not slowed down

I’ve written a tiny script that can be used without changes to your code – it simply overrides functions setTimeout, clearTimeout, setInterval, clearInterval.

Just include it before all your code.

more info here

Third answer

Just do this:

var $div = $('div');
var a = 0;

setInterval(function() {
    a++;
    $div.stop(true,true).css("left", a);
}, 1000 / 30);

Inactive browser tabs buffer some of the setInterval or setTimeout functions.

stop(true,true) will stop all buffered events and execute immediatly only the last animation.

The window.setTimeout() method now clamps to send no more than one timeout per second in inactive tabs. In addition, it now clamps nested timeouts to the smallest value allowed by the HTML5 specification: 4 ms (instead of the 10 ms it used to clamp to).

Reprint:https://stackoverflow.com/questions/5927284/how-can-i-make-setinterval-also-work-when-a-tab-is-inactive-in-chrome
Spread the love

Related articles

Comments are closed.