为啥浏览器不能像游戏引擎那样每秒多次完全渲染 DOM,而不会与性能作斗争?

Posted

技术标签:

【中文标题】为啥浏览器不能像游戏引擎那样每秒多次完全渲染 DOM,而不会与性能作斗争?【英文标题】:Why can't browser fully render the DOM many times per second like game-engines do, without struggling with performance?为什么浏览器不能像游戏引擎那样每秒多次完全渲染 DOM,而不会与性能作斗争? 【发布时间】:2021-01-11 20:44:47 【问题描述】:

我试图理解为什么浏览器每秒多次完全渲染 DOM 是一项艰巨的任务,就像游戏引擎为他们的画布所做的那样。游戏引擎每帧可以执行许多计算,计算光线、阴影、物理等,并且仍然保持无缝的帧速率。 为什么浏览器不能做到这一点,允许每秒多次无缝地重新渲染 DOM?

我知道渲染 DOM 和渲染 Game 场景是两个完全不同的任务,但我不明白为什么后者在性能方面要困难得多。

请尝试关注渲染 DOM 的特定方面,并解释为什么游戏引擎不会面临同样的问题。例如-“浏览器需要解析 html,而游戏的所有代码都已预编译并准备好运行”。

编辑:我编辑了我的问题,因为它被标记为固执己见。我在这里不征求意见,只征求事实。我在问为什么浏览器不能像游戏引擎渲染它们的画布那样每秒完全重新渲染 DOM 60 帧。我知道浏览器面临着更艰巨的任务,但我不明白为什么。请坚持只提供信息丰富的答案,避免发表意见。

【问题讨论】:

我认为 DOM 在现代浏览器中一点也不慢,甚至是移动设备。 这是对浏览器功能的荒谬滥用。 @kundasaba DOM 代表 文档 对象模型。 HTML 代表超 文本 标记语言。如果你尝试用 DOM 修改 HTML 元素来渲染游戏,你会遇到问题。 看看这里 - 这就是游戏所做的 - 他们在显卡上推送非常具体的 c 风格渲染代码,显卡会完成所有渲染计算 - 这在浏览器中不可用级别太高 - 浏览器必须进行更通用的渲染(除非您使用 webGL)opengl.org/archives/resources/code/samples/glut_examples/… 简而言之,复杂的游戏不使用 DOM。图形繁重的应用程序,例如:游戏大多基于画布和/或 webgl。您应该了解他们如何有效地为浏览器制作游戏。 【参考方案1】:

首先,网络游戏很少使用DOM。他们使用更快的Canvas API。 DOM 用于更改 document 上的内容(这就是 DOM 中的 D 所代表的意思),因此它非常不适合游戏。

我的烂手机怎么可能无缝运行使命召唤,却很难写出一个大网页在上面流畅运行?

我从来没有遇到过 DOM 的性能问题。当然,如果你每秒用一个.innerHTML 赋值更新整个<body> 60 次,如果性能不好我不会感到惊讶,因为浏览器需要:

    解析 HTML 并构造 DOM 树; 应用样式并计算每个元素的位置; 渲染元素。

这些步骤中的每一个都需要大量的 CPU 工作,而且在大多数浏览器中,该进程大多是单线程的。

您可以通过以下方式提高性能:

永远不要使用.innerHTML .innerHTML 会使浏览器将 HTML 转换为 DOM 树,反之亦然。使用document.createElement().appendNode()避免更改 DOM。 如果可能,仅更改 CSS 样式。

【讨论】:

但这正是我的问题 - 为什么创建一个可以每秒更新 innerHTML 60 并保持快速的 dom 如此困难,就像游戏一样。 首先感谢您的回答和耐心:) 但是我已经知道并理解了这一切,我自己也是一名网络开发人员,我不明白为什么游戏引擎没有受到影响从同一个问题。当你在游戏中驾驶汽车时,引擎应该计算大量粒子的光影,并且无缝地进行计算 因为游戏引擎不需要将任何文本格式解析为数据结构,也不需要像 CSS 一样计算所有元素的样式。 DOM 并不意味着性能。 所以你是说瓶颈是文本和css的解析? @kundasaba 要回答你的问题why is it so hard to create a dom that could be update the innerHTML,首先这里的“硬”和“慢”是相对的。这一切都归结为您的 DOM 的重量以及您让浏览器重新渲染所有内容的频率。有许多有效的 DOM 操作方法,例如现代 Web 应用程序使用的批量更新和智能差异算法。但这就是网络应用程序的全部内容;对于游戏,这些将不起作用,因为它不是您正在渲染的文档。它们是图形,主要基于 canvas api 或 webgl。【参考方案2】:

游戏是为执行特定于自身的操作而编写的程序 - 它们是用低级语言 asm/c/c++ 或至少可以访问机器级操作的语言编写的。在图形方面,游戏能够将程序推送到图形卡中进行渲染:绘制矢量和着色/光栅化

https://en.wikipedia.org/wiki/OpenGL

https://en.wikipedia.org/wiki/Rasterisation#:~:text=Rasterisation%20(or%20rasterization)%20is%20the,which%20was%20represented%20via%20shapes)

它们还优化了内存、cpu 使用率和 IO。

另一方面,浏览器是具有许多要求的应用程序。

主要设计用于通过创建代表 html 元素的对象来呈现 HTML 文档。浏览器的工作更加复杂,因为它们支持多个版本的 dom 和文档类型 (DTD),以及每个 DTD 所需的相关安全性。

https://en.wikipedia.org/wiki/Document_type_declaration#:~:text=A%20document%20type%20declaration%2C%20or,of%20HTML%202.0%20%2D%204.0)。

并且必须支持渲染一组非常通用的文档——一个页面与另一个页面不同。必须有用于 IO、CSS 解析、图像解析(JPEG、PNG、BMP 等......)和电影播放器​​和相关编解码器、音频播放器及其编解码器和网络摄像头支持的库。此外,它们还支持 javascript 代码环境(不仅是语言,还有 IO 和事件处理),它们还具有对 COM、Java Applets 的历史支持。

这使它们成为非常通用的工具,但重量很重 - 它们携带很多包袱。

图形方面在这方面的性能永远不会像专用程序那样好,因为它们为此类操作提供的 API 总是在更高的级别上运行。

即使是 Canvas API(顾名思义)也是底层渲染库之上的抽象层。每个抽象层都会增加性能。

https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API

为了获得更好的图形性能,现在浏览器中有一个新标准称为 webGL - 虽然这仍然是一个 API,并且在沙箱中运行 - 所以仍然不会像专用代码那样高性能

https://en.wikipedia.org/wiki/WebGL

即使是使用游戏引擎的游戏:Unity、Unreal 也将以比浏览器更专用的方式访问图形功能、CPU、内存和 IO - 因为游戏引擎本身提供专用的渲染和光栅化功能,开发人员可以在他们的游戏中使用以优化图形功能。浏览器不能,因为它们必须涵盖许多通用情况,但不能满足特定要求。

https://docs.unrealengine.com/en-US/Engine/index.html

https://learn.unity.com/tutorial/procedural-sky-19-1

【讨论】:

【参考方案3】:

一般来说,这取决于游戏。最强大的游戏是用 C++ 或 C 引擎开发的,因此它们直接与内存接触并充分利用处理器的能力。

而不是基于 DOM 的网页,它们是通过 JavaScript 等解释性语言编写的。此外,如果网页部署不正确或服务器速度很慢,问题也可能来自服务器。

【讨论】:

以上是关于为啥浏览器不能像游戏引擎那样每秒多次完全渲染 DOM,而不会与性能作斗争?的主要内容,如果未能解决你的问题,请参考以下文章

为啥使用类变量的这段代码不能像在 Java 中那样工作? [复制]

为啥我们不能像在 java 中那样使用 new ClassName() 而不是使用 new ClassName?

为啥 SASS 不能像 `&::not(:first-child)` 那样编译 pseudo_expr?

无法理解 size_hint。为啥这个 .kv 简单的代码不能像我预期的那样工作?

为啥 DirectX/DirectWrite/Direct2D 文本渲染不能像 GDI 一样清晰?

为啥我可以有 OpenGL 着色器类,但不能有 VAO 类?