【问题标题】:setInterval() Not being cleared?setInterval() 没有被清除?
【发布时间】:2016-02-09 19:01:21
【问题描述】:

当用户将焦点切换到另一个浏览器选项卡时,我正在尝试使用页面可见性 api 来暂停画布动画:

var hidden, visibilityChange; 
if (typeof document.hidden !== "undefined") { // Opera 12.10 & Firefox 18 & later support
  hidden = "hidden";
  visibilityChange = "visibilitychange";
} 

function drawStuff () {
  //draws & rotates stuff on canvas
}
function handleVisibilityChange() {
  if (document[hidden]) {
    clearInterval(drawPic);
  } else {
    var drawPic = setInterval(drawStuff, 60);
  }
}

handleVisibilityChange();
document.addEventListener("visibilitychange", handleVisibilityChange, false);

我希望动画能准确地从中断的地方继续,但由于某种原因,每次我离开选项卡并返回到我的页面时,setInterval 都不会清除,并且绘图速度会加快,就好像有多个setIntervals 被调用。如果您多次离开并返回选项卡,动画会加速到荒谬的比例。

这里发生了什么?为什么在 handleVisibilityChange 函数中没有清除间隔?

编辑:移动 var 声明修复它,谢谢。

编辑 2:在 document[hidden] 的代码中添加以供将来参考(如 Suing & Tushar 所述)。

【问题讨论】:

  • 在函数外声明var drawPic;。并从else 中删除var。假设document[hidden] 是正确的。
  • 这是因为drawPic 是一个局部变量,当你尝试清除它时,它会返回 undefined
  • 试试document['hidden']

标签: javascript html canvas


【解决方案1】:

试试这个: 移动“var drawPic;”函数外的声明。如果其他人需要在未来进行测试,还包括其他代码(为了完整起见)。

// 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";
}

function drawStuff () {
  //draws & rotates stuff on canvas
}

var drawPic;

function handleVisibilityChange() {
  if (document[hidden]) {
    clearInterval(drawPic);
  } else {
    drawPic = setInterval(drawStuff, 60);
  }
}

handleVisibilityChange();

// Warn if the browser doesn't support addEventListener or the Page Visibility API
if (typeof document.addEventListener === "undefined" || 
  typeof document[hidden] === "undefined") {
  alert("This demo requires a browser, such as Google Chrome or Firefox, that supports the Page Visibility API.");
} else {
  // Handle page visibility change   
  document.addEventListener(visibilityChange, handleVisibilityChange, false);

}

【讨论】:

  • 您应该解释为使其正常工作所做的更改。你添加了这么多代码,这只是针对旧浏览器所必需的,因此重要的部分不容易看到。
  • t.niese,您的评论已被确认。
【解决方案2】:

更新 在少数 cmets 中。

我犯了一个错误,requestAnimationFrame 不会让计算机自行唤醒。如果您正在播放视频并且可以使用requestAnimationFrame 观看视频,它会。虽然是视频让电脑保持清醒。

此外,术语“focus”可能不正确,但有人建议它仅在“visible”不准确时更新,因为它会在您放置时不断触发窗口上方的另一个窗口,如果该窗口最大化,则事件,或者滚动您正在制作动画的内容。 requestAnimationFrame 也不必显示任何内容,并且调用不知道您在回调正文中做了什么,您可能只是在计算帧数。

现在我将使用术语“页面焦点”,意思是页面是浏览器窗口的显示选项卡,它不必具有系统焦点来触发,但如果有人有一个更准确的描述确实说。

使用window.requestAnimationFrame(functionName);,它会在您失去页面焦点时停止调用,然后在您重新获得页面焦点时再次调用。提供浏览器支持的最大可见帧速率(1/60 秒间隔),并将动画与浏览器的布局和渲染器同步。

有关如何使用和兼容性的详细信息,请参阅MDN requestAnimationFrame

【讨论】:

  • 它甚至比 Page Visibility API 有一个更好的支持
  • 您是对的,使用requestAnimationFrame 的效果应该与您在visibilitychange 事件中列出的效果相同。但是focus 这个词具有误导性,因为它是关于可见性而不是焦点。 requestAnimationFrame 也将在窗口没有焦点但其内容可见时被调用,并且当它具有焦点但窗口的内容不再可见时可能不会被调用。你确定[...]It also keeps the device awake[...] 是在某个地方定义的吗? (我的设备睡着了)
  • @t.niese 确认后,我将移除焦点并替换可见。我从经验中知道让设备保持活力。当我打开(可见)一个使用它的应用程序时,我的机器不会休眠。我使用 Chrome,但我不能确定这是否适用于其他实现,或者它是否是标准的一部分,或者只是浏览器创建者添加的东西。如果需要,将检查和更新。
  • 我在这里在两台设备和两种不同的浏览器上尝试过,并且有一个活动的requestAnimationFrame 并没有让它们保持清醒,所以它要么依赖于设备/浏览器/操作系统,要么你有一些东西在你的将产生此结果的回调。我也没有在规范中看到任何表明这应该保持设备唤醒的内容。
  • @t.niese,无论如何,由于 rAF 比 setInterval 有很多优势,你不应该再使用 setInterval 来做动画。您还可以使用 cancelAnimationFrame() + 可见性 API。
猜你喜欢
  • 2016-03-14
  • 2014-06-22
  • 2019-07-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-23
  • 1970-01-01
相关资源
最近更新 更多