我的JS代码:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var mouse = {x:0,y:0}
const times = [];
let fps;
function refreshLoop() {
window.requestAnimationFrame(() => {
const now = performance.now();
while (times.length > 0 && times[0] <= now - 1000) {
times.shift();
}
times.push(now);
fps = times.length;
refreshLoop();
});
}
refreshLoop();
function draw() {
ctx.fillStyle = "black"
ctx.fillRect(0, 0, c.width, c.height);
ctx.strokeStyle = "white"
ctx.beginPath();
var e = window.event;
ctx.arc(mouse.x, mouse.y, 40, 0, 2*Math.PI);
ctx.stroke();
ctx.font = "30px Comic Sans MS";
ctx.fillStyle = "red";
ctx.textAlign = "center";
ctx.fillText(fps, c.width/2, c.height/2);
}
setInterval(draw, 0);
document.addEventListener('mousemove', function(event){
mouse = { x: event.clientX, y: event.clientY }
})
我的HTML只是画布声明。
据我了解,setinterval(x,0)应该尽可能快地运行,但永远不会超过60fps。我正在尝试达到240+ fps以减少输入延迟。
最佳答案
首先,切勿使用setInterval(fn, lessThan10)
。 fn
很有可能会花费更多的时间来执行,并且您最终可能会堆叠很多fn
调用而根本没有间隔,这可能导致*与众所周知的浏览器crasher®。
*好吧,在正确的实现中,这不应该发生,但是您知道...
现在,您的问题...
您的代码有缺陷。
实际上,您正在同时运行两个不同的循环,不会以相同的时间间隔调用它们。
您正在requestAnimationFrame循环中检查fps,将其设置为与浏览器的绘画速率相同的频率(通常为60 * fps *)。
您正在绘制while(true)
您的两个循环没有链接,因此,在第一个循环中测量的不是您的setInterval(fn, 0)
调用的速率。
有点像你做了
setInterval(checkRate, 16.6);
setInterval(thefuncIWantToMeasure, 0);
显然,您的
draw
无法正确测量checkRate
因此,为了说明
thefuncIWantToMeasure
循环将以更高的速率触发:var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var mouse = {
x: 0,
y: 0
}
const times = [];
let fps;
draw();
function draw() {
const now = performance.now();
while (times.length > 0 && times[0] <= now - 1000) {
times.shift();
}
times.push(now);
fps = times.length;
ctx.fillStyle = "black"
ctx.fillRect(0, 0, c.width, c.height);
ctx.strokeStyle = "white"
ctx.beginPath();
ctx.arc(mouse.x, mouse.y, 40, 0, 2 * Math.PI);
ctx.stroke();
ctx.font = "30px Comic Sans MS";
ctx.fillStyle = "red";
ctx.textAlign = "center";
ctx.fillText(fps, c.width / 2, c.height / 2);
setTimeout(draw, 0);
}
<canvas id="myCanvas"></canvas>
现在,即使嵌套的
setTimeout(fn, 0)
循环比setTimeout
更好,您正在执行的是视觉动画。以比浏览器的绘制速度更快的速度绘制视觉动画是没有意义的,因为您将在此画布上绘制的内容不会被绘制到屏幕上。
如前所述,这正是
setInterval
循环触发的速率。因此,请对所有可视动画使用此方法(至少在必须将其绘制到屏幕上的情况下,在极少数情况下,如果需要,我可以在注释中链接其他方法)。现在要解决您的实际问题,即不是以更高的速率渲染,而是以这种速率处理用户的输入,那么解决方案是拆分您的代码。
将您的图形部分绑定到requestAniamtionFrame循环,不需要变得更快。
更新对象的值,该值应根据用户的输入同步响应用户的手势。不过,请注意,某些用户的手势实际上会以很高的速率触发(例如WheelEvent或窗口的大小调整事件)。通常,您不需要获取所有此类事件的值,因此您可能希望将其绑定到rAF节流阀中。
如果您需要对运动对象进行碰撞检测,请执行数学运算,以从用户手势内部更新运动对象,但不要在屏幕上绘制它。