“现代”浏览器一次可以“处理”多少个 HTML 元素?

Posted

技术标签:

【中文标题】“现代”浏览器一次可以“处理”多少个 HTML 元素?【英文标题】:How many HTML elements can "modern" browsers "handle" at once? 【发布时间】:2014-03-03 22:11:40 【问题描述】:

“现代”,因为该定义可能会随着时间而改变(特别是我的意思是桌面浏览器)

“句柄”,因为这可能会因机器配置/内存而异,但具体而言,我指的是一般用例。


这个问题是在我试图解决涉及大型数据集的特定问题时想到的。

基本上,每当对特定数据集进行更改时,我都会取回完整的数据集,并且必须在浏览器中呈现这些数据。

因此,例如,通过 websocket,我收到一个推送事件,告诉我数据集发生了变化,然后我必须通过抓取现有 DOM 元素、复制它、使用来自此的数据填充元素来以 html 呈现此数据集使用类名或其他元素标识符进行设置,然后将其添加回 DOM。

请记住,此数据集中的任何对象 (JSON) 可能有多达 1000 多个子对象,并且可能有多达 10,000 多个父对象,因此您可以看到可能存在返回的实例数据集向上接近 1,000,000 => 10,000,000 个数据点或更多。

现在,当我必须渲染这些东西时,有趣的部分就来了。对于每个数据点,可能有 3 或 4 个标签用于渲染和设置数据样式,并且这些标签中的任何一个都可能有事件侦听器(可能在父容器上使用委托来减轻负担)。

总而言之,可能需要呈现大量传入信息,我正在尝试找出处理这种情况的最佳方法。

理想情况下,您只想渲染具有更改的单个数据点的更改,而不是重新渲染整个数据集,但由于后端的设计方式,这可能不是一个选项。

我主要关心的是了解浏览器/DOM 的局限性,并通过前端的镜头来看待这个问题。后端肯定会发生一些变化(数据设计、缓存、分页),但这不是这里的重点。

这不是 HTML/DOM 的典型用例,因为我知道存在限制,但它们到底是什么?我们仍然限制在大约 3000-4000 个元素吗?


我有很多 related subquestions 为此我是 actively looking up 但我认为与 *** 社区的其他成员分享一些想法会很好并尝试收集有关此问题的一些信息。

现代浏览器在开始变得缓慢/无响应之前可以处理的“合理”数量的 DOM 元素是多少?

如何对浏览器可以处理的 DOM 元素数量进行基准测试?

有哪些strategies 用于处理需要渲染的大型数据集(分页除外)?

像 mustache 和 handlebars 这样的模板框架在从 data/json(在前端)渲染 html 方面是否比使用 jQuery 或正则表达式更高效?

【问题讨论】:

大型台式机中存在“现代”浏览器,廉价智能手机中存在“现代”浏览器。客户端系统容量将成为您的限制因素。 如果数据集超过 10,000,000 个点,您应该重新考虑这个概念,一次只输出其中的一小部分,因为没有用户愿意在同一页面上浏览 1000 万个元素,或者所以我至少会这么想? 另外,DOM的方面是允许重复使用相同的元素,以HTML5 Canvas为例。 DOM 应该保持动态,并且“对象”应该保留在数据存储中,直到需要为止。在浏览器中达到某种关键元素之前,您更有可能受到错误代码和内存泄漏的限制。 @adeneo 我承认数据的设计方式存在问题,但这本身不是问题。对此有很多后端策略,但我想专注于前端解决方案/限制。 @Pointy 我更专注于尝试了解前端/客户端与 DOM 的局限性,而不是真正尝试解决这里的问题,这只是为了说明。 【参考方案1】:

您的答案是:1 或数百万。我将复制/粘贴关于 SO 的类似问题的答案。

说实话,如果您真的需要这个问题的绝对答案,那么您可能需要重新考虑您的设计。

这里没有给出正确的答案,因为它取决于许多特定于您的应用程序的因素。例如。重与小 CSS 使用、div 大小、实际图形渲染量 每个 div 需要,目标浏览器/平台,DOM 事件数 听众等。

仅仅因为你可以并不意味着你应该! :-)"

见:how many div's can you have before the dom slows and becomes unstable?

这确实是一个无法回答的问题,太多的因素在太多的角度。然而,我会这么说,在单个页面加载中,我使用 1 毫秒的 javascript setinterval 不断地将新的 div 添加到 ID 递增 1 的页面。我的 Chrome 浏览器刚刚超过 20,000,并且正在使用 600MB 内存。

【讨论】:

在我之前对这个问题的探索中,浏览器似乎会在内存过载之前徘徊在大约 3000-4000 个 dom 元素上。必须有一种方法来对此进行基准测试,我还没有发现任何明显的东西。 这真的取决于 DOM 元素中的内容,我只是添加了空 div。我刚刚关闭了我的浏览器,因为它接近一个完整的 GB Ram 以避免崩溃,它几乎是 40k。我也在使用 vPro I7 CPU。 说得好。有这么多因素,这个问题类似于“汽车能跑多快”。虽然我会说,这一行在不同浏览器上测试过的问题,再加上关于对现代桌面硬件的合理期望的调查信息,将提供一些富有成效的结果。 我使用名为 2DX 的框架加载了一个包含 100 万个 TD 元素和 4 个字符串的表格。浏览器内存增加了 2.2 GB。以每 20 000 个震颤的 600mb 计算,加起来将达到 30 GB。链接是js2dx.com @tremor,存在直接关系,但不是完全线性的。关系的系数取决于实现。根据我对一个特定浏览器的测试,它实际上几乎是线性的。能详细点吗?【参考方案2】:

这是一个只有精通统计的答案才能准确和全面的问题。

为什么

适当的等式是这样的,其中 N 是节点数,bytesN 是在 DOM 中表示它们所需的总字节数,节点索引范围是 n ∈ [0, N),bytesOverhead 是具有绝对最小属性配置且没有 innerHTML 的节点使用的内存量,bytesContent 是用于填充这样一个最小节点的内存量。

字节N = ∑N (bytesContentn + bytesOverheadn)

问题中要求的值是在最坏情况下手持设备、操作系统、浏览器和操作条件下 N 的最大值。为每个排列求解 N 并非易事。上面的等式揭示了三个依赖关系,每个依赖关系都可能彻底改变答案。

依赖关系

    节点的平均大小取决于每个节点用于保存内容的平均字节数,例如 UTF-8 文本、属性名称和值或缓存信息。 DOM 对象的平均开销取决于管理每个文档的 DOM 表示的 HTTP 用户代理。 W3C 的Document Object Model FAQ 指出,“虽然所有 DOM 实现都应该是可互操作的,但它们在代码大小、内存需求和单个操作的性能方面可能会有很大差异。” 可用于 DOM 表示的内存取决于默认使用的浏览器(取决于手持设备供应商或用户喜欢的浏览器)、用户对默认浏览器的覆盖、操作系统版本、内存容量手持设备、常见后台任务和其他内存消耗。

严谨的解决方案

可以运行测试来确定手持设备上使用的每个常见 http 用户代理的 (1) 和 (2)。任何给定站点的用户代理分布可以通过配置 Web 服务器的日志机制来获得 HTTP_USER_AGENT 如果默认情况下不存在,然后在日志中剥离除该字段之外的所有字段并计算每个值的实例.

需要针对属性值和 UTF-8 内部文本(或任何编码)测试每个字符的字节数,以获得用于计算 (1) 的明确因素对。

可用内存也需要在各种常见条件下进行测试,这本身就是一个重大的研究项目。

选择的 N 的特定值必须为零才能处理实际的最坏情况,因此人们会选择一定百分比的内容、节点结构和运行时间条件的典型情况。例如,可以使用某种形式的随机原位(在正常环境条件下)研究对案例进行抽样,并找到满足 95% 的案例的 N。

也许可以通过上述方式对一组案例进行测试,并将结果放在一个表格中。这样可以直接回答您的问题。

我猜想,一个受过良好教育的移动软件工程师需要数学,尤其是统计方面的专长,花五周的全职工作时间才能获得合理的结果。

更实际的估计

人们可以猜测最坏的情况。经过一整天的研究和一些概念验证应用程序,这个提议可以得到改进。没有时间这样做,这是一个很好的初步猜测。

考虑一个允许 1 GB 用于 DOM 的手机,因为正常操作条件使用 4 GB 中的 3 GB 用于上述目的。人们可能会假设一个节点的平均内存消耗如下,以获得一个大概的数字。

每个字符 2 个字节,每个节点 40 个字符的内部文本 每个字符 2 个字节,用于 4 个属性值,每个属性值 10 个字符 4 个属性名称每个字符 1 个字节,每个属性名称 4 个字符 在效率较低的情况下,C/C++ 节点开销为 160 字节

在这种情况下,Nworst_case,最坏情况的最大节点数,

= 1,024 X 1,024 X 1,024
  / (2 X 40  +  2 X 4 X 10  +  1 X 4 X 4  +  160)

= 3,195,660 . 190,476.

但是,如果可以避免的话,我不会在具有 300 万个 DOM 节点的浏览器中构建文档。考虑采用以下更常见的做法。

常见做法

最好的解决方案是远低于 Nworst_case 可能的值,并使用标准 HTTP 设计技术将节点总数减少到可能的程度。

减少任何给定页面上显示的内容的大小和复杂性,这也提高了视觉和概念上的清晰度。 从服务器请求最少量的数据,使用窗口技​​术推迟尚不可见的内容,或以精心策划的方式平衡响应时间和内存消耗。 使用异步调用来协助实现上述极简主义。

【讨论】:

您的 160 字节 C++ 开销似乎是一个错误的估计。上面的数字表明在 C++ 中使用的每个元素更多 10-30kb。我是一个忙碌的经验丰富的 C++ 程序员,我害怕 DOM 节点的共谋,但即使我也会低估它 50%。【参考方案3】:

对于那些想知道的人:Google 有它的 Dom 大小推荐

Domsize recommandations


"

最佳 DOM 树:

总共少于 1500 个节点。 最大深度为 32 个节点。 没有超过 60 个子节点的父节点。

一般来说,寻找方法仅在需要时创建 DOM 节点,并在不再需要时销毁它们。

如果您的服务器提供大型 DOM 树,请尝试加载您的页面并手动注意显示哪些节点。也许您可以从加载的文档中删除未显示的节点,并仅在用户手势(例如滚动或按钮单击)后创建它们。

如果您在运行时创建 DOM 节点,Subtree Modification DOM Change Breakpoints 可以帮助您确定何时创建节点。

如果您无法避免使用大型 DOM 树,另一种提高渲染性能的方法是简化 CSS 选择器。请参阅减少样式计算的范围和复杂性。

"

【讨论】:

【参考方案4】:

DOM 元素变得过多的方式有很多种。这是一个 React + d3 组件,我一直在使用它来渲染许多元素并更真实地了解 DOM 的限制:

export const App = React.memo((props) => 
  const gridRef = React.useRef(null);
  React.useEffect(() => 
    if (gridRef.current) 
      const table = select(gridRef.current);
      table
        .selectAll("div")
        .data([...new Array(10000)])
        .enter()
        .append("div")
        .text(() => "testing");
    
    if (props.onElementRendered) 
      props.onElementRendered();
    
  , []);
  return <div ref=gridRef />;
);

在运行 Chrome 的 16GB 内存的 2021 年 Macbook Pro 上,我发现从大约 30,000 个元素开始出现严重延迟(我认为是在绘制步骤上)

【讨论】:

以上是关于“现代”浏览器一次可以“处理”多少个 HTML 元素?的主要内容,如果未能解决你的问题,请参考以下文章

一次可以处理多少个请求

高斯消元处理无解|多解情况 poj1830

现代浏览器中当前的 cookie 限制是多少?

任何现代文件系统都支持任意元数据处理吗?

在性能下降之前,浏览器可以安全地处理多少个元素 ID?

你猜一个 TCP 连接上面能发多少个 HTTP 请求