jar*_*lli 49 javascript optimization performance canvas
随着Canvas仍然是互联网的新手,并且没有任何迹象表明我将来可以看到,它没有太多记录在案的"最佳实践"或其他非常重要的技巧,这些技巧对于开发来说是"必须知道的"它在任何一个特定的地方.像这样的事情散落在不太知名的地方,很多次.
人们需要了解的东西太多了,而且还要学到很多东西.
我想分享一些东西,以帮助那些正在学习Canvas的人,也许还有一些已经非常了解它的人,并希望从其他人那里获得一些关于他们认为最佳实践或其他使用HTML5中的Canvas的提示和技巧的反馈.
我想从一个我个人认为对开发人员来说非常有用但非常罕见的事情开始.
就像你在任何其他时间一样,无论情况如何,用任何其他语言.它是其他一切的最佳实践,我发现在复杂的画布应用程序中,在处理几个不同的上下文和保存/恢复状态时,事情会变得有些混乱.更不用说代码更具可读性和整体清晰度.
例如:
...
// Try to tell me this doesn't make sense to do
ctx.fillStyle = 'red';
ctx.fill();
ctx.save();
if (thing < 3) {
// indenting
ctx.beginPath();
ctx.arc(2, 6, 11, 0, Math.PI*2, true);
ctx.closePath();
ctx.beginPath();
ctx.moveTo(20, 40);
ctx.lineTo(10, 200);
ctx.moveTo(20, 40);
ctx.lineTo(100, 40);
ctx.closePath();
ctx.save();
ctx.fillStyle = 'blue'
ctx.fill();
ctx.restore();
} else {
// no indenting
ctx.drawImage(img, 0, 0, 200, 200);
ctx.save();
ctx.shadowBlur();
ctx.beginPath();
ctx.arc(2, 60, 10, 0, Math.PI*2, false);
ctx.closePath();
ctx.fillStyle 'green';
ctx.fill();
ctx.restore();
}
ctx.restore();
ctx.drawRect();
ctx.fill();
...
Run Code Online (Sandbox Code Playgroud)
IF语句是不是更容易和更清晰地阅读和知道什么是立即发生在这里的ELSE声明?你能看到我在这说什么吗?我认为这应该是开发人员应该继续练习的方法,就像编写简单的'ol javascript或任何其他语言一样.
setInterval和setTimeout从未打算用作动画定时器,它们只是在一段时间延迟后调用函数的通用方法.如果将来设置间隔为20ms,但是您的函数队列需要的时间比执行的时间长,那么在这些函数完成之后才会触发计时器.这可能是一段时间,这在动画方面并不理想.RequestAnimationFrame是一种告诉浏览器正在进行动画的方法,因此它可以相应地优化重新绘制.它还会限制非活动标签的动画,因此如果您在后台打开它,它不会杀死您的移动设备的电池.
Nicholas Zakas 在他的博客上写了一篇关于requestAnimationFrame的非常详细和内容丰富的文章,值得一读.如果你想要一些硬性和快速的实现指令,那么Paul Irish已经编写了一个requestAnimationFrame垫片 - 这就是我在最近所使用的每一个Canvas应用程序中使用的内容.
Joe Lambert甚至比使用requestAnimationFrame代替setTimeout和setInterval更好,编写了一个名为requestInterval和requestTimeout 的新的改进的垫片,他解释了使用requestAnimFrame时存在的问题.您可以查看脚本的要点.
现在所有的浏览器已经赶上了这个规范,对requestAnimFrame()polyfill进行了更新,这个更新可能仍然是用来覆盖所有供应商的.
@nicolahibbert在她关于优化Canvas游戏的帖子中写到的动画重型游戏技术提到,使用多个相互叠加的画布可能会更好,而不是在单个画布中完成所有操作.尼古拉解释说"同时在同一个画布上画太多像素会导致你的帧速率从地板上掉落.以Breakout为例.试图绘制砖块,球,桨,任何能量提升或武器,然后每个明星在后台 - 这根本不起作用,依次执行每个指令需要太长时间.通过将星空和游戏的其余部分分成单独的画布,你可以确保一个像样的帧率".
我必须为我制作的一些应用程序执行此操作,包括三星的Olympic Genome Project facebook应用程序.知道并利用它是否需要是非常有用的.它极大地减少了加载时间,而且它可能是一种非常有用的技术,可以将图像加载到屏幕外,因为它们有时需要一段时间.
var tmpCanvas = document.createElement('canvas'),
tmpCtx = tmpCanvas.getContext('2d'),
img = document.createElement('img');
img.onload = function() {
tmpCtx.drawImage(thumbImg, 0, 0, 200, 200);
};
img.src = '/some/image/source.png';
Run Code Online (Sandbox Code Playgroud)
请注意,图像的src在加载后设置.这是记住要做的关键事情.一旦图像完成加载并绘制到这些临时画布中,您就可以使用相同的ctx.drawImage()将它们绘制到主画布,但不是将图像作为第一个参数,而是使用'tmpCtx.canvas'引用临时画布.
2d上下文具有对其相关DOM元素的后引用:
var ctx = doc.getElementById('canvas').getContext('2d');
console.log(ctx.canvas); // HTMLCanvasElement
Run Code Online (Sandbox Code Playgroud)
我很想听到其他人的更多信息.我正在制定一份我们应该标准化的事项列表,以便为我公司的前端代码标准和最佳实践添加新的部分.我希望尽可能多地获得这方面的反馈.
jar*_*lli 17
动画的最佳画布优化技术是限制每帧上清除/绘制的像素数量.最简单的实现方法是重置整个canvas元素并重新绘制所有内容,但这对浏览器来说是一项昂贵的操作.
在帧之间重用尽可能多的像素.这意味着每帧需要处理的像素越少,程序运行的速度就越快.例如,当使用clearRect(x,y,w,h)方法擦除像素时,仅清除和重绘已更改的像素而非整个画布非常有用.
从程序上生成图形通常是要走的路,但有时候这不是最有效的.如果您使用实心填充绘制简单形状,则以程序方式绘制它们是最好的方法.但是如果你用笔画,渐变填充和其他性能敏感的化妆来绘制更详细的实体,你最好使用图像精灵.
可以将两者混合起来.在应用程序启动时,在画布上以程序方式绘制图形实体.之后,您可以通过绘制它们的副本来重复使用相同的精灵,而不是重复生成相同的阴影,渐变和笔触.
画布可以通过旋转和缩放等变换进行操作,从而导致画布坐标系发生变化.这是了解两种方法可用的状态堆栈的重要之处:context.save()(将当前状态推送到堆栈)和context.restore()(恢复到先前的状态).这使您可以将转换应用于绘图,然后还原回以前的状态,以确保下一个形状不受任何早期转换的影响.状态还包括填充和描边颜色等属性.
使用canvas时,一个非常强大的工具是合成模式,其中包括允许屏蔽和分层.有大量可用的复合模式,它们都是通过画布上下文的globalCompositeOperation属性设置的.复合模式也是状态堆栈属性的一部分,因此您可以应用复合操作,堆叠状态并应用另一个,并还原到您创建第一个之前的状态.这可能特别有用.
为了允许子像素绘图,canvas的所有浏览器实现都采用抗锯齿(尽管这似乎不是HTML5规范中的要求).如果要绘制清晰的线条并注意结果看起来模糊,请记住消除锯齿的重要性.发生这种情况是因为浏览器会插入图像,就好像它实际上是在这些像素之间.它可以产生更平滑的动画(每次更新可以真正移动半个像素),但它会让你的图像显得模糊.
要解决此问题,您需要舍入到整数值或偏移半个像素,具体取决于您是否正在绘制填充或描边.
如果在Canvas元素上调用drawImage,如果将x和y位置舍入为整数,则速度会快得多.
这是jsperf的测试用例,显示使用整数与使用小数相比要快多少.
因此,在渲染之前将x和y位置四舍五入为整数.
另一个jsperf测试显示 Math.round()不一定是舍入数字的最快方法.使用按位破解实际上比内置方法更快.
要清除任何现有像素context.clearRect(x,y,w,h)的整个画布,通常会使用 - 但还有另一个选项可用.每当设置画布的宽度/高度时,即使它们重复设置为相同的值,也会重置画布.在使用动态大小的画布时,这很有用,因为您会注意到图形消失.
Chrome开发者工具分析器非常有用,可以找出您的性能瓶颈.根据您的应用程序,您可能需要重构程序的某些部分,以提高性能以及浏览器如何处理代码的特定部分.
| 归档时间: |
|
| 查看次数: |
20574 次 |
| 最近记录: |