如何使Chrome浏览器中的选项卡处于非活动状态时也可以使用setInterval?

我有一个setInterval每秒运行一段代码30次。 这很好,但是当我select另一个选项卡(使我的代码选项卡变为不活动), setInterval由于某种原因被设置为空闲状态。

我做了这个简化的testing用例( http://jsfiddle.net/7f6DX/3/ ):

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

如果您运行此代码,然后切换到另一个选项卡,请等待几秒钟,然后返回,animation在您切换到另一个选项卡时的位置继续。 因此,如果选项卡处于非活动状态,则animation不会每秒运行30次。 这可以通过计算每秒调用setInterval函数的次数来确认 – 如果选项卡处于非活动状态,则不会是30,而只会是1或2。

我想这是通过devise完成,以提高性能,但是有什么办法来禁用这种行为? 这在我的情况下实际上是一个缺点。

在大多数浏览器中,非活动选项卡的优先级较低,这会影响JavaScript计时器。

如果您的转换值是使用帧间实时消逝计算的而不是固定每个间隔的增量,则不仅可以解决此问题,还可以使用requestAnimationFrame实现窒息animation,因为如果处理器不是很忙。

下面是一个使用requestAnimationFrame的animation属性转换的香草JavaScript示例:

 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> 

我遇到了与audio衰落和HTML5播放器相同的问题。 当标签变为非活动状态时,它被阻塞了。 所以我发现一个WebWorker允许使用间隔/超时没有限制。 我用它来发布“蜱”的主要JavaScript。

WebWorkers代码:

 var fading = false; var interval; self.addEventListener('message', function(e){ switch (e.data) { case 'start': if (!fading){ fading = true; interval = setInterval(function(){ self.postMessage('tick'); }, 50); } break; case 'stop': clearInterval(interval); fading = false; break; }; }, false); 

主Javascript:

 var player = new Audio(); player.fader = new Worker('js/fader.js'); player.faderPosition = 0.0; player.faderTargetVolume = 1.0; player.faderCallback = function(){}; player.fadeTo = function(volume, func){ console.log('fadeTo called'); if (func) this.faderCallback = func; this.faderTargetVolume = volume; this.fader.postMessage('start'); } player.fader.addEventListener('message', function(e){ console.log('fader tick'); if (player.faderTargetVolume > player.volume){ player.faderPosition -= 0.02; } else { player.faderPosition += 0.02; } var newVolume = Math.pow(player.faderPosition - 1, 2); if (newVolume > 0.999){ player.volume = newVolume = 1.0; player.fader.postMessage('stop'); player.faderCallback(); } else if (newVolume < 0.001) { player.volume = newVolume = 0.0; player.fader.postMessage('stop'); player.faderCallback(); } else { player.volume = newVolume; } }); 

有一个使用Web Workers的解决scheme(如前所述),因为它们在单独的进程中运行,并且不会变慢

我写了一个小脚本,可以在不改变你的代码的情况下使用它 – 它只是覆盖函数setTimeout,clearTimeout,setInterval,clearInterval

只需在您的代码之前包含它

http://github.com/turuslan/HackTimer

只要这样做:

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

不活动的浏览器选项卡缓冲一些setIntervalsetTimeout函数。

stop(true,true)将停止所有缓冲事件,立即执行最后一个animation。

window.setTimeout()方法现在限制在非活动选项卡中每秒发送一次超时。 另外,它现在将嵌套的超时设置为HTML5规范允许的最小值:4 ms(而不是用来钳位的10 ms)。

我认为对这个问题的最好的理解是在这个例子中: http : //jsfiddle.net/TAHDb/

我在这里做一个简单的事情:

间隔1秒,每次隐藏第一个跨度并移动到最后,显示第二个跨度。

如果你停留在页面上,它的工作原理就是这样。 但是,如果你隐藏了几秒钟的标签,当你回来时,你会看到一个厌倦的事情。

就像你现在不活跃的时间里所有的事情一样,所有的事情都会一次发生。 所以几秒钟后你会得到像X事件。 他们是如此之快,可以看到所有6跨度一次。

所以它接缝铬只延迟事件,所以当你回来的所有事件会发生,但一次…

一个实用的应用程序是这样一个简单的幻灯片。 想象一下这些数字是图像,如果用户回来时隐藏标签,他会看到所有的图像浮动,完全mesed。

为了解决这个问题,使用stop(true,true)来告诉pimvdb。 这将清除事件队列。

这是我粗略的解决scheme

 (function(){ var index = 1; var intervals = {}, timeouts = {}; function postMessageHandler(e) { window.postMessage('', "*"); var now = new Date().getTime(); sysFunc._each.call(timeouts, function(ind, obj) { var targetTime = obj[1]; if (now >= targetTime) { obj[0](); delete timeouts[ind]; } }); sysFunc._each.call(intervals, function(ind, obj) { var startTime = obj[1]; var func = obj[0]; var ms = obj[2]; if (now >= startTime + ms) { func(); obj[1] = new Date().getTime(); } }); } window.addEventListener("message", postMessageHandler, true); window.postMessage('', "*"); function _setTimeout(func, ms) { timeouts[index] = [func, new Date().getTime() + ms]; return index++; } function _setInterval(func, ms) { intervals[index] = [func, new Date().getTime(), ms]; return index++; } function _clearInterval(ind) { if (intervals[ind]) { delete intervals[ind] } } function _clearTimeout(ind) { if (timeouts[ind]) { delete timeouts[ind] } } var intervalIndex = _setInterval(function() { console.log('every 100ms'); }, 100); _setTimeout(function() { console.log('run after 200ms'); }, 200); _setTimeout(function() { console.log('closing the one that\'s 100ms'); _clearInterval(intervalIndex) }, 2000); window._setTimeout = _setTimeout; window._setInterval = _setInterval; window._clearTimeout = _clearTimeout; window._clearInterval = _clearInterval; })(); 

受到Ruslan Tushov的图书馆的巨大影响,我创build了自己的小型图书馆 。 只需在<head>添加脚本,它将使用WebWorker修补setIntervalsetTimeout

我能够使用audio标签和处理其ontimeupdate事件至less250毫秒调用我的callback函数。 它在一秒钟内被称为3-4次。 它比滞后一秒钟更好