关于javascript:为什么我需要取消CancelAnimationFrame()

Why would I ever need to cancelAnimationFrame()

我不明白为什么API包含cancelAnimationFrame(),因为
我可以通过设置continue变量来停止动画,如下所示:

1
2
3
function draw(timestamp) {
  if (continue == true) { requestAnimationFrame(draw); }
}

所以问题是在什么情况下我应该使用cancelAnimationFrame()?


首先,重要的参考点。 (日期)(候选推荐书)规范:http://www.w3.org/TR/animation-timing/#definitions

Associated with every Document is an animation frame request callback list, which is a list of tuples. handle is an integer ^[long] that uniquely identifies the entry in the list. callback is a FrameRequestCallback object. Initially, the animation frame request callback list for a Document is empty.

另外,请记住,这些规范的目标受众是用户代理开发人员。在这些规范的实现中,用户代理向我们(应用程序开发人员)提供了一个与之交互的API。

注意上面的每个文档情感;您可以在window或上下文中包含多个文档。浏览上下文中可以有多个上下文。

那么,这与每个文档有何关系?好吧,(推荐)规范引用了过程模型,该模型实质上将所有这些列表都转储到一个空列表中,并对该"保留"列表的结果执行回调调用算法。.但是,再次,这可能不是问题作为我们的应用程序开发人员; *我想,我们作为应用程序开发人员,不会在我们自己的window上下文的多个文档中以及整个文档中跟踪和维护甚至Document.FrameRequestList实例。我们仅与window上可访问的API接口。

现在,让我们总结requestAnimationFrame()的实际作用以及返回的结果。

调用requestAnimationFrame并提供function作为回调,会在动画帧请求回调列表中添加一个条目()。 requestAnimationFrame返回Handler [long]

根据上述规范(http://www.w3.org/TR/animation-timing/#dom-windowanimationtiming-cancelanimationframe),

The cancelAnimationFrame method is used to cancel a previously made request to schedule an animation frame update.

可以推断出,通过调用cancelAnimationFrame并提供(可能是先前存储的)handle作为参数,可以从动画帧请求回调列表中删除一项,但情况并非如此。

When cancelAnimationFrame(handle) is called, the user agent must set the cancelled flag to true for the callback registered on this Document whose handle is handle. The cancelled flag is set whether the callback is in a animation frame request callback list or not. If there is no callback with the given handle, then this function does nothing.

因此,您在cancelAnimationFrame中提供的handle不会修改列表。它将"取消"标志设置为true(在回调中),这实际上使它无法运行。这是合理的,因为上述(上面的)处理模型。

因此,对于您的问题(以及对您的问题的特定评论),跳过向文档的动画帧请求回调列表添加条目的操作,使用requestAnimationFrame不会保留现有的scheduled条目(或已取消标记为false的现有条目)。需要考虑一个"更大"的上下文和处理模型(包括文档页面可见性属性)。

在您的问题中,有人提到作为注释,您可能希望取消特定的场景框架请求,但是出于无意的方面和考虑,这样做的更好理由。

简而言之,如果您要使用API??请求执行回调的框架更新,请使用API??取消/停止所述更新请求并停止回调。


FWIW并完成接受的答案:

我来这里是为了了解使用requestAnimationFrame调度的函数是否会抛出错误,该函数会使在执行时已从DOM中删除(又称为卸载)的元素发生突变。它不是,即:

1
2
3
4
5
6
let el = document.getElementById('element');
setTimeout(() => el.remove(), 20);
setTimeout(() => {
  el.style.transform = 'scale(2)'
  console.log(el instanceof HTMLElement) // el is kept in memory but removed from the DOM
, 40) // true`.

综上所述,您应该使用cancelAnimationFrame来防止由requestAnimationFrame自动安排的功能带来的副作用,并且您可以选择使用它来进行(微)优化,即使它没有副作用也可以避免执行。