据我了解,JS requestAnimationFrame
API的使用是针对帧率不需要控制的情况,但我有一个用例,其中<canvas>
至关重要仅以某个fps间隔更新,该间隔可能介于1到25之间(即每秒1到25个帧,即)。那么我可以以某种方式仍然有效地使用rAF来实现它提供的优化吗?
This question与我有相似之处,但在那个问题的背景下,我接受的答案对我来说几乎没有任何意义。
我有两个可能的解决方案。第一个涉及使用while
循环来停止脚本执行指定的延迟,然后再从回调中调用requestAnimationFrame
。在我看到这个的例子中,它有效地限制了动画的fps,但它似乎也减慢了整个标签的速度。这仍然是一个很好的解决方案吗?如上所述的问题中提到的第二种方法是在requestAnimationFrame
内调用setInterval
。对我来说似乎有点费解,但它可能是最好的选择吗?
还是有更好的选择来实现这个目标吗?
答案 0 :(得分:14)
Yoshi的答案可能是解决这个问题的最佳代码。但我仍然认为这个答案是正确的,因为经过一些研究后我基本上发现我的问题无效。 requestAnimationFrame
实际上是为了保持帧速率尽可能高,并且优化了动画要保持一致和平滑的场景。
值得注意的是,你不需要requestAnimationFrame
来获得优化(即使rAF被吹捧为一个出色的性能助推器),因为浏览器仍然优化<canvas>
的常规绘制。例如,当标签没有聚焦时,Chrome for one会停止绘制其画布。
所以我的结论是这个问题无效。希望这有助于任何想要与我相似的人。
答案 1 :(得分:9)
这只是一个概念证明。
我们所做的就是设置每秒帧数和每帧之间的间隔。在绘图功能中,我们从当前时间中扣除最后一帧的执行时间,以检查自上一帧起经过的时间是否大于我们的间隔(基于fps)。如果条件的计算结果为true,我们将设置当前帧的时间,该时间将是下一个绘图调用中的“最后一帧执行时间”。
var Timer = function(callback, fps){
var now = 0;
var delta = 0;
var then = Date.now();
var frames = 0;
var oldtime = 0;
fps = 1000 / (this.fps || fps || 60);
return requestAnimationFrame(function loop(time){
requestAnimationFrame(loop);
now = Date.now();
delta = now - then;
if (delta > fps) {
// Update time stuffs
then = now - (delta % fps);
// Calculate the frames per second.
frames = 1000 / (time - oldtime)
oldtime = time;
// Call the callback-function and pass
// our current frame into it.
callback(frames);
}
});
};
用法:
var set;
document.onclick = function(){
set = true;
};
Timer(function(fps){
if(set) this.fps = 30;
console.log(fps);
}, 5);
答案 2 :(得分:5)
你可以做什么,虽然我真的不知道这是否真的更好:
requestAnimationFrame
setInterval
的可见上下文
示例:
<canvas id="canvas"></canvas>
<script type="text/javascript">
(function () {
var
ctxVisible = document.getElementById('canvas').getContext('2d'),
ctxHidden = document.createElement('canvas').getContext('2d');
// quick anim sample
(function () {
var x = 0, y = 75;
(function animLoop() {
// too lazy to use a polyfill here
webkitRequestAnimationFrame(animLoop);
ctxHidden.clearRect(0, 0, 300, 150);
ctxHidden.fillStyle = 'black';
ctxHidden.fillRect(x - 1, y - 1, 3, 3);
x += 1;
if (x > 300) {
x = 0;
}
}());
}());
// copy the hidden ctx to the visible ctx on a fixed interval (25 fps)
setInterval(function () {
ctxVisible.putImageData(ctxHidden.getImageData(0, 0, ctxHidden.canvas.width, ctxHidden.canvas.height), 0, 0);
}, 1000/40);
}());
</script>