我是否达到了浏览器中JavaScript对象的大小限制?
我在我的HTML中的<script>
标签embedded一个大数组,像这样(毫不奇怪):
<script> var largeArray = [/* lots of stuff in here */]; </script>
在这个特定的例子中,数组有210,000个元素。 这远低于2 31的理论最大值 – 4个数量级 。 下面是有趣的部分:如果我将JS的源代码保存到一个文件中,那么这个文件> 44兆字节(准确的说是46,573,399字节)。
如果你想自己看,你可以从GitHub下载 。 (所有的数据都是jar装的,大量的数据都是重复的,生产中不会这样)。
现在,我真的不关心提供这么多的数据。 我的服务器gzip它的响应,所以它真的不需要很长时间才能通过线路获取数据。 然而,页面一旦加载就会使浏览器崩溃 。 我没有在IE中testing(这是一个内部工具)。 我的主要目标是Chrome 8和Firefox 3.6。
在Firefox中,我可以在控制台中看到一个相当有用的错误:
Error: script stack space quota is exhausted
在Chrome中,我只是得到了悲伤标签页面:
已经切入了追逐
- 这对我们现代的“高性能”浏览器来说真的太多了吗?
- 有什么我可以做*优雅地处理这么多的数据?
顺便说一下,我可以在Chrome中开启和closures此function(请阅读:不会使标签崩溃)。 我真的认为,铬,至less,是由更棘手的东西,但显然我错了…
编辑1
@蜡笔小新:我并不想certificate我为什么要把这么多的数据一次性转储到浏览器中。 简短的版本:要么我解决这个问题(当然不是那么容易),要么解决其他一些问题。 现在我正在select更简单的方法。
@various:现在,我并不特别想find方法来减less数组中元素的数量。 我知道我可以实现Ajax分页或什么是你,但是在其他方面为我介绍了自己的一系列问题。
@Progrog:每个元素看起来像这样:
{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}
@威尔:但是我有一台带有4核心处理器的计算机,6GB的内存,超过半个TB的磁盘空间……我甚至不要求浏览器快速完成这个工作 – 我只是问它为所有工作! ☹
编辑2
任务完成!
随着Juan和Guffa的点名提示 ,我能够得到这个工作! 这似乎是问题只是在parsing源代码,而不是实际在内存中使用它。
总结胡安的回答评论泥潭:我不得不把我的大arrays分成一系列较小的Array#concat()
,然后Array#concat()
他们,但这是不够的。 我也必须把它们放入单独的var
语句中。 喜欢这个:
var arr0 = [...]; var arr1 = [...]; var arr2 = [...]; /* ... */ var bigArray = arr0.concat(arr1, arr2, ...);
致力于解决此问题的每个人: 谢谢。 第一轮在我身上!
*显而易见的是:向浏览器发送较less的数据
这就是我想要的:你说这是一个44MB的文件。 这肯定需要超过44MB的内存,我猜这需要大大超过44MB的内存,也许是半个演出。 你可以减less数据,直到浏览器不崩溃,看看有多less内存浏览器使用?
即使仅在服务器上运行的应用程序也能很好地读取44MB文件并将其保存在内存中。 说了这么多,我相信浏览器应该能够处理它,所以让我跑一些testing。
(使用Windows 7,4GB的内存)
第一个testing我把这个arrays减半,没有问题,使用80MB,没有崩溃
第二次testing我将数组拆分成两个单独的数组,但仍包含所有数据,使用160Mb,没有崩溃
第三个testing由于Firefox说它已经用完了,问题可能是它不能一次parsing数组。 我创build了两个单独的数组,arr1,arr2然后做了arr3 = arr1.concat(arr2); 它运行良好,只使用了更多的内存,大约165MB。
第四个testing我创build了这些数组中的7个(每个22MB),并将它们连接起来以testing浏览器的限制。 大约需要10秒钟才能完成加载。 内存高达1.3GB,然后回落到500MB。 所以是铬可以处理它。 它不能一次parsing它,因为它使用某种recursion,因为控制台的错误信息可以注意到。
解决scheme创build单独的数组(每个小于20MB),然后连接它们。 每个数组应该在自己的var语句中,而不是使用单个var进行多个声明。
我仍然会考虑只提取必要的部分,可能会使浏览器呆滞。 但是,如果是内部任务,这应该没问题。
最后一点:你不是在最大的内存水平,只是最大的parsing水平。
是的,要求浏览器太多了。
如果数据已经是数据,那么这个数据量将是可pipe理的,但它不是数据。 考虑到浏览器必须parsing这个庞大的源代码块,同时检查语法的总和。 一旦parsing成有效的代码,代码就必须运行以产生实际的数组。
所以,所有的数据将一次存在于(至less)两个或三个版本中,每个都有一定的开销。 由于数组文字是一个单一的语句,每个步骤将不得不包括所有的数据。
将数据分成几个较小的数组可能会使浏览器更容易。
你真的需要所有的数据吗? 你不能只使用AJAXstream传输当前所需的数据吗? 与Google地图类似,您无法将所有地图数据放入浏览器的内存,只显示您当前所看到的部分。
请记住,在浏览器的内部表示中,可以将40多个硬数据膨胀得更多。 例如,JS解释器可能使用散列表来实现数组,这会增加额外的内存开销。 另外,我期望浏览器同时存储源代码和JS内存,这就使数据量增加了一倍。
JS旨在提供客户端的UI交互,而不是处理大量的数据。
编辑:
顺便说一句,你真的认为用户会喜欢下载40兆字节的代码? 还有不less用户使用宽带上网不到。 脚本的执行将被暂停,直到所有的数据被下载。
EDIT2:
我看了一下数据。 该数组肯定会被表示为散列表。 还有很多项目是对象,这将需要参考跟踪…这是额外的内存。
如果它是简单的原始数据向量,我想性能会更好。
编辑3:数据当然可以简化。 它的大部分是重复的string,可以以某种方式编码为整数或其他东西。 另外,我的Opera在显示文本时遇到了麻烦,更不用说解释了。
编辑4: 忘记DateTime对象 ! 使用Unix时代的时间戳或string,但不是对象!
EDIT5:你的处理器并不重要,因为JS是单线程的。 而且你的内存也不重要,大多数浏览器都是32位的,所以他们不能使用那么多的内存。
编辑6: 尝试将数组索引更改为顺序整数 (0,1,2,3 …)。 这可能会使浏览器使用更高效的数组数据结构。 您可以使用常量来高效地访问数组项目。 这将大大减less数组的大小。
尝试使用Ajax作为JSON页面检索数据。 我不知道确切的大小,但我已经能够以这种方式将大量数据导入Google Chrome。
使用延迟加载。 有指针的数据,并得到它时,用户要求。
这种技术被用于各种地方来pipe理数百万条数据logging。
[编辑]
我find了我正在寻找的东西。 在jqgrid中虚拟滚动。 这是500Klogging被延迟加载。
我会尝试把它作为一个大string与每个“项目”之间的分隔符,然后使用split
,如:
var largeString = "item1,item2,......."; var largeArray = largeString.split(",");
希望string不会如此快地耗尽堆栈。
编辑:为了testing它,我创build了20万个简单项目(每个项目一个数字)的虚拟数组,并在一瞬间内加载Chrome。 200万件? 几秒钟,但没有崩溃。 6,000,000个项目数组(50 MB文件)使Chrome加载了大约10秒,但仍然没有崩溃。
所以这导致我相信问题不是数组本身,而是它的内容 。优化内容到简单的项目,然后parsing它们“在飞行”,它应该工作。