我正在学习JavaScript,有8年的Python经验,作为练习,我做了一个曼德尔布罗特渲染器,生成分形并使用 putImageData
来从左到右更新画布,每次更新一个单像素列。
我发现,采用这种方法,浏览器中的可见图像只有在全屏计算完成后才会更新(而不是像我所希望的那样看到它从左到右逐渐出现)。我理解这是预期的行为,所以我决定通过使用以下方法来添加 "扫描线 "动画 requestAnimationFrame
. (就像这里看到的那样。Christian Stigen Larsen渲染器)
我的期望是,较轻的计算应该渲染得更快(因为下一帧很快就可以使用),而较高迭代的计算应该渲染得更慢。我在我的实现中发现,扫描线的速度一直很慢。
我已经将这个问题与我的曼德尔布罗特计算隔离开来,因为这种行为也发生在下面的最小情况下。我在Chrome 83浏览器上运行,看到画布以恒定的速度(大约每秒30个像素)从左到右缓慢填充。
是我的 rAF 实现不正确,还是我的期望值有问题?我链接到的渲染器使用的是 setTimeout()
来制作动画,但我读到这是目前广泛不鼓励的做法。
我应该如何以最高的可用帧率(目前我并不担心限制帧率)实现画布的从左到右扫描更新?
EDIT: 为了清楚起见,下面的代码是在RAF的每一帧请求中画一个薄薄的矩形,并取下 恰恰 绘制整个画布所需的时间与100次迭代的Mandelbrot渲染所需的时间相同。
这说明它的慢并不是由于帧之间的计算量造成的。
const canvas = document.querySelector('.myCanvas');
const width = window.innerWidth;
const height = window.innerHeight;
const ctx = canvas.getContext('2d');
function anim(timestamp, i) {
if (i < width) {
ctx.fillRect(i, 0, 1, height);
window.requestAnimationFrame(function(timestamp) {
anim(timestamp, i + 1);
})
}
}
ctx.fillStyle = 'rgb(0,0,0)';
window.requestAnimationFrame(function(timestamp) {
anim(timestamp, 0);
});
<!DOCTYPE html>
<html lang="en">
<head>
<canvas class="myCanvas">
<p>Add suitable fallback here.</p>
</canvas>
<script src="slow%20rAF.js"></script>
<style>
body {
margin: 0;
overflow: hidden;
}
</style>
<meta charset="UTF-8">
<title>Mandelbrot</title>
</head>
<body>
</body>
</html>
没有 "更快的 "requestAnimationFrame。
一般来说,答案是将计算和渲染分开。理想情况下,计算发生在主线程之外,渲染则在主线程上处理。即使没有线程,你也应该能够找到一种方法在 RAF 之外进行计算,并让 RAF 渲染像素。