如何使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
只需在您的代码之前包含它
只要这样做:
var $div = $('div'); var a = 0; setInterval(function() { a++; $div.stop(true,true).css("left", a); }, 1000 / 30);
不活动的浏览器选项卡缓冲一些setInterval
或setTimeout
函数。
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
修补setInterval
和setTimeout
。
我能够使用audio标签和处理其ontimeupdate事件至less250毫秒调用我的callback函数。 它在一秒钟内被称为3-4次。 它比滞后一秒钟更好