我是否已经达到浏览器中 JavaScript 可以处理的对象大小的极限了?

我在 HTML 中的 <script>标记中嵌入了一个大型数组,如下所示(这并不奇怪) :

<script>
var largeArray = [/* lots of stuff in here */];
</script>

在这个例子中,数组有210,000个元素。这远低于理论上的最大值231-by 数量级。这里是有趣的部分: 如果我将数组的 JS 源代码保存到一个文件中,该文件大于44兆字节(确切地说是46,573,399字节)。

如果你想亲眼看看,你可以 从 GitHub 下载。(里面的所有数据都是罐装的,所以很多数据都是重复的。在生产过程中不会出现这种情况。)

现在,我真的不担心 服务有那么多的数据。我的服务器 gzip 它的响应,所以它真的不需要所有那么长的时间来获得通过线路的数据。然而,有一个真正令人讨厌的趋势,页面,一旦加载,以 撞车的浏览器。我根本没有在 IE 中测试(这是一个内部工具)。我的主要目标是 Chrome 8和 Firefox 3.6。

在 Firefox 中,我可以在控制台中看到一个相当有用的错误:

Error: script stack space quota is exhausted

在 Chrome 浏览器中,我只是看到了悲伤标签页:

enter image description here

直奔主题吧

  • 这是 真的太多的数据,我们的现代,“高性能”浏览器处理?
  • 有没有什么我可以做 * 的优雅处理这么多数据?

顺便说一下,我能够让这个工作(读: 不崩溃的标签)在 Chrome 中断断续续。我真的以为 Chrome 至少是由更坚固的东西组成的,但显然我错了... ..。


编辑1

@ Crayon: 我不是想证明 为什么的合理性,我想把这么多的数据一次性扔进浏览器。简而言之: 要么我解决这个问题(当然不是那么容易) ,要么我必须解决一大堆其他问题。我现在选择更简单的方法。

@ different: 现在,我并没有特别寻找减少数组中元素数量的方法。我知道我可以实现 Ajax 分页或者诸如此类的东西,但是这会在其他方面给我带来一系列问题。

@ Phrogz: 每个元素看起来都像这样:

{dateTime:new Date(1296176400000),
terminalId:'terminal999',
'General___BuildVersion':'10.05a_V110119_Beta',
'SSM___ExtId':26680,
'MD_CDMA_NETLOADER_NO_BCAST___Valid':'false',
'MD_CDMA_NETLOADER_NO_BCAST___PngAttempt':0}

@ Will: 但是我有一台4核处理器的电脑,6GB 的内存,超过半 TB 的磁盘空间... ... 我甚至不要求浏览器快速完成这些——我只是要求它能工作 完全没有! something


编辑2

任务完成!

有了来自 胡安以及 Guffa的正确建议,我能够让这个工作!看起来问题只存在于 解析的源代码中,实际上并没有在内存中使用它。

总结一下胡安的回答: 我不得不把我的大数组分成一系列的小数组,然后 Array#concat()它们,但这还不够。我 还有必须把它们放在单独的 var语句中。像这样:

var arr0 = [...];
var arr1 = [...];
var arr2 = [...];
/* ... */
var bigArray = arr0.concat(arr1, arr2, ...);

对每一个为解决这个问题做出贡献的人: 谢谢你。第一轮我请!


* 除了显而易见的: 向浏览器发送更少的数据

39420 次浏览

你真的需要所有的数据吗?你不能流只是当前需要使用 AJAX 的数据?类似于谷歌地图-你不能把所有的地图数据放入浏览器的内存中,它们只显示你当前看到的部分。

请记住,40兆的硬数据可以膨胀到更多的浏览器的内部表示。例如,JS 解释器可能使用散列表来实现数组,这将增加额外的内存开销。另外,我希望浏览器同时存储源代码和 JS 内存,这样单独就可以使数据量增加一倍。

JS 旨在提供客户端 UI 交互,而不是处理大量数据。

编辑:

顺便说一句,你真的认为用户会喜欢下载40MB 的代码吗?仍然有许多用户的宽带互联网接入不足。并且脚本的执行将被暂停,直到所有数据被下载。

编辑2:

我看了一下数据。该数组肯定会表示为散列表。另外,许多项目是对象,这将需要引用跟踪... 这是额外的内存。

我想如果它是原始数据的简单向量,性能会更好。

编辑3: 数据当然可以简化,大部分是重复的字符串,可以进行编码 以某种方式作为整数或东西。此外,我的 Opera 在显示文本时遇到了麻烦,更不用说解释它了。

编辑4: 忘记 DateTime 对象! 使用 unix 时代的时间戳或字符串,但不要使用对象!

编辑5: 您的处理器并不重要,因为 JS 是单线程的。而且你的内存也不重要,大多数浏览器是32位的,所以他们不能使用太多的内存。

编辑6: 尝试将数组索引更改为连续整数(0,1,2,3...)。这可能会使浏览器使用更有效的数组。可以使用常数有效地访问数组项。这将大大减少数组的大小。

尝试使用 Ajax 作为 JSON 页面检索数据。我不知道确切的大小,但我已经能够拉大量的数据到谷歌浏览器的方式。

我会尝试将它作为一个大字符串,每个“条目”之间有一个分隔符,然后使用 split,类似于:

var largeString = "item1,item2,.......";
var largeArray = largeString.split(",");

希望字符串不会这么快耗尽堆栈。

编辑: 为了测试它,我创建了一个包含200,000个简单项目(每个项目一个数字)的虚拟数组,Chrome 在一瞬间加载了它。200万件?几秒钟,但没有撞车。6,000,000条目数组(50 MB 文件)使 Chrome 的加载时间约为10秒,但仍然没有崩溃。

这让我相信问题不在于数组本身而在于 内容。.将内容优化为简单的项目,然后“动态”解析它们,应该就可以了。

使用延迟加载。使用指向数据的指针,并在用户询问时获取数据。

这种技术在许多地方被用来管理数百万的数据记录。

[编辑]

我找到了我要找的。在 Jqgrid中的虚拟滚动。这是50万记录被懒惰加载。

是的,对于一个浏览器来说要求太高了。

如果这些数据已经是数据,那么它们是可以管理的,但是它们还不是数据。考虑到浏览器必须解析大量的源代码块,同时检查语法是否合理。一旦解析成有效的代码,代码必须运行才能生成实际的数组。

因此,所有数据将同时存在于(至少)两个或三个版本中,每个版本都有一定的开销。由于数组文字是一个单独的语句,因此每个步骤都必须包含所有的数据。

将数据划分为几个较小的数组可能会使浏览器更加方便。

这就是我想尝试的: 你说它是一个44 MB 的文件。这肯定需要超过44MB 的内存,我猜这需要超过44MB 的内存,也许是半个 G。你能不能在浏览器不崩溃之前减少数据量,看看浏览器使用了多少内存?

即使是只在服务器上运行的应用程序也可以很好地避免读取44MB 的文件并将其保存在内存中。说了这么多,我相信浏览器应该能够处理它,所以让我运行一些测试。

(使用 Windows 7,4GB 内存)

第一次测试 我把数组切成两半,没有问题,使用80MB,没有崩溃

第二次测试 我把数组分成两个独立的数组,但仍然包含所有的数据,使用160Mb,没有崩溃

第三次测试 由于 Firefox 说堆栈用完了,问题可能是它不能立即解析数组。我创建了两个单独的数组 arr1和 arr2,然后执行 arr3 = arr1.concat (arr2) ; 它运行良好,只需要稍微多一点内存,大约165MB。

第四个测试 我创建了其中的7个数组(每个22MB)并连接它们以测试浏览器限制。页面完成加载大约需要10秒钟。内存上升到1.3 GB,然后下降到500 MB。所以是的,铬可以处理它。它只是不能一次解析所有内容,因为它使用某种递归,控制台的错误消息可以注意到这一点。

回答 创建单独的数组(每个小于20MB) ,然后连接它们。每个数组都应该使用自己的 var 语句,而不是使用单个 var 进行多个声明。

我仍然会考虑只获取必要的部分,这可能会使浏览器变慢。然而,如果这是一个内部任务,这应该没问题。

最后一点: 您没有处于最大内存级别,只是处于最大解析级别。