我正在尝试构建一个流畅的 60fps 动画浏览器 JavaScript 循环。我注意到垃圾收集器启动并向动画帧添加可变的非零时间。我首先跟踪代码中的分配情况,然后隔离循环本身。我正在使用
requestAnimationFrame
并发现在所谓的“空”循环上它仍然会导致每次迭代分配并触发垃圾收集器。令人沮丧的是,这似乎也发生在其他循环机制 setInterval
和 setTimeout
中。
下面我整理了一些 jsfiddles 和屏幕截图,演示了示例“空循环”。所有样本均来自约 5 秒的时间线。
此时,我正在寻找最小化垃圾收集的最佳解决方案。从下面的示例来看,requestAnimationFrame 是这方面最糟糕的选择。
请求动画框架
https://jsfiddle.net/kevzettler/e8stfjx9/
var frame = function(){
window.requestAnimationFrame(frame);
};
window.requestAnimationFrame(frame);
设置间隔
https://jsfiddle.net/kevzettler/p5LbL1am/
var frame = function(){
//literally nothing
};
window.setInterval(frame, 0);
设置超时
https://jsfiddle.net/kevzettler/9gcs6gqp/
var frame = function(){
window.setTimeout(frame, 0);
}
window.setTimeout(frame, 0);
我实际上不确定,但我似乎记得网络工作人员有自己的垃圾收集器,因此 GC 命中不会影响主线程中的 FPS(尽管它仍然会影响更新发送到主线程)
我不是专家,但根据我所读到的内容。我也遇到了您在评论中提到的相同错误报告:
按照建议,在每次调用时分配 Number 对象,将与垃圾收集相符。
https://bugs.chromium.org/p/chromium/issues/detail?id=120186#c20
它还表明,仅仅打开调试器来记录堆栈跟踪可能会导致问题。不知道远程调试的时候是不是也是这样?
这个答案建议在动画帧之间进行翻转,以减少垃圾收集:https://stackoverflow.com/a/23129638/141022
从你问的问题的深度来看,我确定我是什么 即将要说的内容对您来说是显而易见的,但重新关注可能会有兴趣 你的总体目标(尽管可能对你的目标没有帮助) Chrome 的有趣观察)。
我们需要记住的一件事是我们并不是要避免 完全垃圾收集,因为它是 JS 的基础。相反,我们是 希望尽可能地减少它以适应渲染我们的 16ms 的帧(以获得 60fps)。
VelocityJs 的方法之一是使用单个全局“tick”来处理所有动画...
定时器是在 setInterval()、setTimeout() 和 使用requestAnimationFrame()。有两个性能问题 创建计时器:1)同时触发太多计时器会减少帧数 由于浏览器维护它们的开销而产生的费率,以及 2) 不正确地标记动画开始的时间会导致 丢帧。
Velocity 对第一个问题的解决方案是维护单一 全局刻度循环,循环遍历所有活动的 Velocity 动画 一次。不会为每个速度动画创建单独的计时器。 简而言之,Velocity 优先考虑调度而不是中断。
http://www.sitepoint.com/incredible-fast-ui-animation-using-velocity-js/
这与减少垃圾收集的一般做法一起,例如创建回收缓存以重用对象,甚至重写数组切片等方法以避免垃圾。