Javascript 为什么这个画布代码这么慢?
我有一个简短的代码,在这些轨道上画圆(轨道)点(卫星)。卫星正在绕轨道运行。事实上,代码不是我的,但我被要求解决这个问题 根据chrome和firefox中的profiler,functionJavascript 为什么这个画布代码这么慢?,javascript,canvas,webgl,Javascript,Canvas,Webgl,我有一个简短的代码,在这些轨道上画圆(轨道)点(卫星)。卫星正在绕轨道运行。事实上,代码不是我的,但我被要求解决这个问题 根据chrome和firefox中的profiler,functiondrawSatellite消耗了50%-100%的cpu,我想知道原因 画布与您的窗口一样大(1920x1080)。大约有160个轨道(随着page上线时间的增加而增加) 这是绘图卫星: OrbitBackground.prototype.drawSatellite = function(ctx, sate
drawSatellite
消耗了50%-100%的cpu,我想知道原因
画布与您的窗口一样大(1920x1080)。大约有160个轨道(随着page上线时间的增加而增加)
这是绘图卫星
:
OrbitBackground.prototype.drawSatellite = function(ctx, satellite) {
ctx.fillStyle = satellite.satellite.fill;
ctx.beginPath();
if (++satellite.satellite.angularPosition == 360)
satellite.satellite.angularPosition = 0;
// 1 FPS = 60 calls => 180 / 6 (6-times faster @ 60 FPS) = 30
var radians = satellite.satellite.angularPosition * Math.PI / 30 / satellite.rps;
if (satellite.backward)
radians = -radians;
ctx.arc(
satellite.satellite.x + satellite.orbit.radius * Math.cos(radians),
satellite.satellite.y + satellite.orbit.radius * Math.sin(radians),
satellite.satellite.radius,
0,
Math.PI*2,
true
);
ctx.closePath();
ctx.fill();
};
调用它的函数:
OrbitBackground.prototype.drawFrame = function() {
if (this.running)
requestAnimationFrame(this.drawFrame.bind(this));
this.dynamicStageCtx.clearRect(0, 0, this.pageWidth, this.pageHeight);
for (var i=0; i < this.orbits.length; i++) {
this.drawSatellite(this.dynamicStageCtx, this.orbits[i]);
}
};
OrbitBackground.prototype.drawFrame=函数(){
如果(这个正在运行)
requestAnimationFrame(this.drawFrame.bind(this));
this.dynamicStageCtx.clearRect(0,0,this.pageWidth,this.pageHeight);
对于(var i=0;i
您正在这样做:
Loop:
set fill style
begin path
make path
end path
fill
set fill style (just once, before loop)
begin path (just one path, with loop-number of subpaths)
Loop:
moveTo (start of subpath)
make path
close path
fill (just once, after loop)
这样做会更快:
Loop:
set fill style
begin path
make path
end path
fill
set fill style (just once, before loop)
begin path (just one path, with loop-number of subpaths)
Loop:
moveTo (start of subpath)
make path
close path
fill (just once, after loop)
但这要求每个卫星上的填充样式都相同。如果只有几种颜色,你可以试着用它们的颜色把它们捆起来
还要注意的是,计算余弦和正弦的速度很慢(所有的触发函数和平方根调用都很慢),如果你能避免使用它们,你会更好
画布的大小(像素数)也很重要。考虑制作画布一半大小或四分之一大小(960x540或480x270),并用CSS缩放。 你这样做:
Loop:
set fill style
begin path
make path
end path
fill
set fill style (just once, before loop)
begin path (just one path, with loop-number of subpaths)
Loop:
moveTo (start of subpath)
make path
close path
fill (just once, after loop)
这样做会更快:
Loop:
set fill style
begin path
make path
end path
fill
set fill style (just once, before loop)
begin path (just one path, with loop-number of subpaths)
Loop:
moveTo (start of subpath)
make path
close path
fill (just once, after loop)
但这要求每个卫星上的填充样式都相同。如果只有几种颜色,你可以试着用它们的颜色把它们捆起来
还要注意的是,计算余弦和正弦的速度很慢(所有的触发函数和平方根调用都很慢),如果你能避免使用它们,你会更好
画布的大小(像素数)也很重要。考虑制作画布的一半大小或四分之一大小(960x540或480x270),并用CSS缩放它。
<强>可能是个问题:>/P> 在您的ctx.arc命令之前,我没有看到ctx.beginPath
如果没有ctx.beginPath,您以前的所有弧都将与当前弧一起重新绘制 小优化 将Math.PI*2分配给变量,因为它经常使用var PI2=Math.PI*2;
如何消除代码中最慢的部分(Math.cos和Math.sin)。
由于节点处于重复轨道中,因此可以预先计算完整轨道的所有未转换[x,y]
var statellite.orbitTrig=[];
for(var i=0;i<360;i++){
var radians=PI2/360*i;
var x=satellite.orbit.radius * Math.cos(radians)
var y=satellite.orbit.radius * Math.sin(radians)
satellite.orbitTrig.push({x:x,y:y});
}
可能有问题: 在您的ctx.arc命令之前,我没有看到ctx.beginPath 如果没有ctx.beginPath,您以前的所有弧都将与当前弧一起重新绘制 小优化 将Math.PI*2分配给变量,因为它经常使用
var PI2=Math.PI*2;
如何消除代码中最慢的部分(Math.cos和Math.sin)。
由于节点处于重复轨道中,因此可以预先计算完整轨道的所有未转换[x,y]
var statellite.orbitTrig=[];
for(var i=0;i<360;i++){
var radians=PI2/360*i;
var x=satellite.orbit.radius * Math.cos(radians)
var y=satellite.orbit.radius * Math.sin(radians)
satellite.orbitTrig.push({x:x,y:y});
}
我认为问题可能是,我们使用画布作为2D上下文,使用javascript函数而不是着色器,所以操作可能太繁重,因为cpu无法为每个帧调用所有这些javascript函数?但这只是一个理论…你的FPS太低了吗?高CPU消耗并不总是意味着代码速度慢或不是最优的。你需要注意的是,你的draw方法的运行速度比(1000/targetFPS)要快。msIn chrome fps还可以,在firefox中fps非常低,有时浏览器会死机。在嵌入式系统上,fps是超低的。1)缓存:satellite.satellite可以缓存以避免6次访问,satellite.orbit.radius也可以缓存。2) 填什么?规范化填充对性能有好处:创建填充后,执行ctx.fillStyle=myFill;然后myFill=ctx.fillStyle;所以fill的格式完全正确。3) 尝试使用fillRect以查看圆形绘制是否不是瓶颈。4) 请注意,FF和Ch都有画布调试/分析工具。嗯,我尝试了两个示例。至少在我的机器上,我认为问题可能是,我们使用画布作为2D上下文,使用javascript函数而不是着色器,所以操作可能太繁重,因为cpu无法为每个帧调用所有这些javascript函数?但这只是一个理论…你的FPS太低了吗?高CPU消耗并不总是意味着代码速度慢或不是最优的。你需要注意的是,你的draw方法的运行速度比(1000/targetFPS)要快。msIn chrome fps还可以,在firefox中fps非常低,有时浏览器会死机。在嵌入式系统上,fps是超低的。1)缓存:satellite.satellite可以缓存以避免6次访问,satellite.orbit.radius也可以缓存。2) 填什么?规范化填充对性能有好处:创建填充后,执行ctx.fillStyle=myFill;然后myFill=ctx.fillStyle;所以fill的格式完全正确。3) 尝试使用fillRect以查看圆形绘制是否不是瓶颈。4) 请注意,FF和Ch都有画布调试/分析工具。嗯,我尝试了两个示例。至少在我的机器上,谢谢你的建议。画布不能更小,因为它应该是页面的背景,所以它取决于客户端屏幕。事实上,我的颜色很少,所以我会尝试将它们组合在一起。画布可以更小,然后用CSS放大到其大小的两倍或三倍,但这需要fidelityThx的损失作为好的建议。画布不能更小,因为它应该是页面的背景,所以它取决于客户端屏幕。事实上,我没有多少颜色,所以我会尝试将它们组合在一起。画布可以更小,然后用CSS放大到其大小的两倍或三倍,但这会损失逼真度