游戏邦在:
杂志专栏:
gamerboom.com订阅到鲜果订阅到抓虾google reader订阅到有道订阅到QQ邮箱订阅到帮看

比较更新DOM格式游戏对象的4种方式

发布时间:2011-08-30 16:47:16 Tags:,,,,

作者:Louis Stowasser

若你选择在游戏中使用DOM格式,而非SVG或canvas。很好!DOM格式是个杰出综合解决方案。本文通过研究四种以DOM格式更新游戏对象的方式,说明哪种方式效果最佳。

HTML5 game from html5trends.com

HTML5 game from html5trends.com

用于图表的测试包含变更游戏对象位置,以及反复更新。但也随机调整少数对象,旨在促使整个测试更具公平性。

以下是测试这些方式的脚本。

测试 1:InnerHTML

innerHTML是通过网页页面更新内容最传统的方式,同时也是创造DOM元素最快速和最普遍的方式。任何Element对象都具有此属性。Element对象赋值后就会开始分析数值,这是由于HTML在字符串中创造新Element对象。

此测试包含循环机制,所有更新都通过innerHTML以及回归游戏对象中的HTML字符串,重新渲染DOM树状图。

测试2:修改所有样式属性

这是游戏开发的标准方式,此测试将样式属性调整至新数值(游戏邦注:例如左边、顶部、宽度、高度和背景、各种着色)。这些调用只会带来Repaint活动,所以从理论角度看,这应该是最迅速的。

但这有点违反直觉,因为我们设定的属性也许不会发生改变,因此纯属浪费时间。这将我们带入下个测试。

测试3:修改变更属性

和上个测试类似,待到渲染时刻,我们通过存储上个数值检查属性是否发生改变。若发生改变,样式属性就得到更新。问题是我们需要编写更多代码,借用更多存储空间,带来更多Repaint情况,因此会降低运作性能。

测试4:调节器

上个测试有些与众不同——我们并非借助游戏循环机制反复更新游戏对象,而是借助调节器,它只有在被修改情况下才会进行重新渲染。调节器,或访问器,和运用属性类似,除非我们能够准确把握设定或访问装置时会发生什么情况。

注意:调节器的兼容性不高。Webkit和Mozilla都支持defineSetter,虽然defineSetter已被弃用,但其运作速度似乎最快。Opera和IE9可以充分利用Object.defineProperty。

在此测试中,属性X有接收器和调节器。当X被赋值,调节器就启动。然后调节器就会将样式属性(左边)调整至新数值。

循环机制生成后,只有修改后的属性会获得更新,它们一经调整就会立即更新(游戏邦注:而非待到下个游戏循环更新出现)。这具有很多优点,但也带来许多问题。假设我们需要设置众多属性,频繁更新属性意味着需要执行多个调节装置,每个循环更新会带来许多Repaint活动。

结果

大量推测后,下面来看看若干图表数据!

chart from html5grind.com

chart from html5grind.com

从图表中我们可以发现修改前检验数值是最迅速的方式,第二快的方式是使用调节器。

在我更早的测试版本中,背景图像会重新应用至各着色操作,着色极大影响运作性能。移除此内容后,测试速度就会翻倍。因此,有个小建议:不要每次着色都更新图像。

调节器似乎是个不错的解决方案,因为你无需通过游戏循环机制维持渲染效果,而且调节器运作迅速。但在游戏中,这并非总是理想方式;一次更新众多属性意味着所有调整属性都需要调用函数,更别说所有调整行为带来的Repaint活动。此外,由于早前提到的兼容问题,利用调节器并不切实际。

所有浏览器操作数据均显示,innerHTML是最缓慢的方式,因此应排除在外。

我们可以得出的结论是需保持追踪测量数值,仅在必要时候调整属性。另一注意点是更新图像(游戏邦注:例如背景属性)会极大影响运作性能,即便图像保持一致。

令人惊讶的是,即便未发生任何变化,调整属性也会极大影响内容运作性能。我最初的猜测是浏览器会获悉何时需进行调整,但其实并非如此。此外,设置前检验数值是否发生变化更快速。(本文为游戏邦/gamerboom.com编译,如需转载请联系:游戏邦

Improving DOM Performance for HTML5 Games

By Louis Stowasser

So you’ve chosen to use the DOM for your game instead of SVG or canvas. Great! Using the DOM is a great all-around solution, and this article will look into four ways to update game objects in the DOM to find which performs best.

The tests used for the graphs involved changing the position of game objects and updating many many times. Only some objects were changed randomly to make it more fair.

The test script used to benchmark these methods is here. Feel free to run it and to leave your feedback in a comment at the end of this post.

Test 1: InnerHTML

innerHTML is the oldest way of updating content on a web page, and it’s the fastest and the most widely used method of creating DOM elements. Any Element object will have this property. Once assigned a value it will parse the value as HTML creating new Element objects from the string.

This test involves a loop in which each iteration re-renders the DOM tree by using innerHTML and returning the HTML string from the game objects.

Test 2: Modify all the style properties

A fairly standard method in game development, this test sets the style properties to their new value, such as left, top, width, height and background, on every render(). With all the calls one after another, only one Repaint event should be triggered, so in theory this should be the quickest.

However, this might seem counterintuitive because we are setting properties that may not have changed and are therefore wasting time. This leads us to the next test.

Test 3: Modify changed properties

Similar to the last test, when it is time to render we check if the property has changed by storing the last value. If it has changed, then the style property is updated. The problem is that more code needs to be written, more memory is used, and more Repaint events might be triggered, thus reducing performance.

Test 4: Setters

The last test is a bit different — Instead of having a game loop that renders our game objects iteratively, we use setters that only re-render when modified. A setter, or accessor, is just like using a property except we can decide exactly what happens when setting or getting it.

Note: Compatibility isn’t great with setters. Webkit and Mozilla supports __defineSetter__ and even though is deprecated, seems to be the fastest. Opera and IE9 can make use of Object.defineProperty.

In this test there is a getter and setter for the property x. When x is assigned a value the setter is invoked. The setter then changes the style property (left) to the new value.

Now, when the loop runs, only the properties that were modified will be updated, and they’ll be updated as soon as they are changed — not when the next iteration of the game loop occurs. This has many benefits but also causes some problems. Say we need to set lots of properties and frequently — updating a property means that more than one setter function is executed and multiple Repaint events are fired per loop iteration.

Results

Enough speculation. Let’s look at some graphs!

We can see from the graphs that checking the value before modifying is the fastest method, and the second-fastest is to use setters.

In my earlier version of the tests, the background image was reapplied on each render which was drastically affecting the performance. Once I removed this the tests doubled in speed. Thus, a handy tip: don’t update the image on every render.

Setters look like a nice solution as you don’t need a game loop to maintain the rendering and setters are quite quick. But in games this is not always ideal; updating many properties at once would mean a function call for every changed property, not to mention a Repaint event for every modification. Also, due to compatibility issues mentioned earlier, using setters isn’t really practical.

All of the browsers report innerHTML as the slowest method so that is out of the question.

The conclusion we can draw is you should keep track of your values and only modify the property if it needs changing. The other crucial thing to notice is updating the image, such as the background property, affects the performance drastically, even if it is the same image.

It’s suprising to see that modifying the properties even where nothing has changed has quite an affect on performance. My initial speculation was that the browser would know if it needs to change, but this appears to not be the case. Checking if the value changed before setting it is faster.(Source:html5grind


上一篇:

下一篇: