13

我目前正在编写一个应用程序,它在 HTML5 画布上显示很多,我的意思是,很多 2D 路径(由数百、数千个小段组成)。通常,几百万点。这些点从服务器下载到二进制文件ArrayBuffer中。

我可能不会在现实世界中使用那么多点,但我对如何提高性能有点兴趣。如果你愿意,你可以称之为好奇心;)

无论如何,我已经测试了以下解决方案:

  1. 使用gl.LINESgl.LINE_STRIPWebGL一起使用,并在 GPU 上的着色器中计算所有内容。目前最快的,可以在我的 Macbook Air 上显示多达1000 万段而不会退缩。但是如果你想避免在 JavaScript 中处理东西,那么二进制格式有非常严格的限制,这很慢。

  2. 使用Canvas2Dstroke() ,在一次调用中绘制一条包含所有段的巨大路径。当我超过100k 点时,页面会在画布更新之前冻结几秒钟。所以,不在这里工作。

  3. 使用Canvas2D,但使用自己的stroke()调用绘制每条路径。尽管其他人在互联网上一直在说,这比一次调用绘制所有内容要快得多,但仍然比 WebGL 慢得多。当我达到大约500k 段时,事情开始变得糟糕。

这两种 Canvas2D 解决方案需要循环遍历 JavaScript 中所有路径的所有点,因此速度很慢。您是否知道任何可以提高 JavaScript 在 ArrayBuffer 中的迭代速度或一般处理速度的方法?

但是,奇怪的是,在所有画布绘制调用完成后,屏幕并没有立即更新。当我开始达到性能极限时,在绘制调用结束和画布更新之间存在明显的延迟。你知道这是从哪里来的吗?有没有办法减少它?

4

1 回答 1

8

首先,WebGL 是一个不错的炒作想法,但解码和显示二进制数据所需的处理量在着色器中根本不起作用,所以我排除了它。

这是我遇到的主要瓶颈。其中一些在一般编程中很常见,但记住它们是个好主意:

  • 最好使用多个for小循环
  • 尽可能在最高级别创建变量和闭包,不要在 for 循环中创建它们
  • 以块的形式呈现您的数据,并setTimeout在几毫秒后用于安排下一个块:这样,用户仍然可以使用 UI
  • JavaScript 对象和数组既快又便宜,请使用它们。最好从头到尾按顺序读取/写入它们。
  • 如果您不在数组中顺序写入数据,请使用对象 (因为非顺序读写对对象来说很便宜)并将索引推送到索引数组中。我使用了一个 SortedList 实现来保持索引的排序,我在这里找到了。开销很小(大约是渲染时间的 10-20%),最终它是非常值得的。

这就是我记得的一切。如果我确实找到了其他东西,我会更新这个答案!

于 2012-06-21T18:20:35.313 回答