我们正在尝试在Firefox 28上使用html5和indexeddb构建基于客户端的应用程序。大型数据首次加载到firefox,首次使用的是AJAX请求的json格式。每个json resposnse大约2MB(gzip),数据将存储到indexeddb IDBWrapper。
随着响应,firefox中的内存使用量迅速增加。当我们运行大约12个响应时,firefox的内存将增长到大约1GB(总共3GB),有时它会导致AJAX错误。成功加载后,内存将直接降至500MB或更低。
似乎在整个加载/存储过程中,firefox没有机会进行GC,我们尝试在每个响应之间使用setTimeout,但似乎无能为力。
我的问题是,有没有其他方法可以在加载大json时减少firefox的内存使用量?
编辑: 代码是这样的:
$.ajax({
url : URL['getData'],
dataType : "json",
data : {
startDate : _startDate,
endDate : _endDate,
format : "json"
},
async : true,
success : function(_data) {
_data = null;
// store to indexeddb
_callback();
},
error : function() {
setCurrentDataLabel('Error', 0);
}
});
我将sotre的部分删除到indexeddb以使其变得简单。有趣的是,记忆也迅速增加。但是,如果我将dataType : "json"
更改为dataType : "text"
,则内存使用量会非常小,GC显然会运行。在处理json时,似乎firefox有一些性能问题。
答案 0 :(得分:3)
服务器端分页
如果"服务器"问题是运行一些编程语言/框架,如果您可以轻松地对该服务器上运行的代码进行更改,那么最简单的方法就是@Coder
在评论中提到的内容。即:服务器端分页。
我将@Coder
离开,为服务器分页提供答案"情况下。
客户端流式传输
另一方面,如果没有代码,您可以在服务器上进行更改(例如:它是由某些其他进程生成的静态JSON文件,并且有' s只有一个简单的静态HTTP服务器)然后你可能想采用我在评论中提到的方法,即:让客户端进行流式传输。
采用这种方法:
XMLHttpRequest
(AJAX),您在Firefox中使用本机平台API({{1} })。注1:
您无法在服务器端(显式或自动)使用GZIP编码,仍然可以在客户端上进行流式读取。您必须明确配置服务器以仅提供未压缩的JSON,或者您可以简单地使用StreamListener
标头要求服务器不向您发送压缩内容(要求不存在压缩)方案如Accept-Encoding:
)。
注2:
您无法通过内容'进行此类HTTP请求。 JavaScript(即:Web服务器提供的JavaScript内容)。您只能通过特权' JavaScript(例如:在Firefox插件中)。
沙盒HTTP请求
我不会包含一个自己提出请求的例子(它非常大),但你基本上只能剪切&从MDN上的Creating Sandboxed HTTP Connections页面粘贴第一个(最简单的)示例。
在示例中,在dont-compress-please
回调中,他们只是将读取的文本添加到缓冲区(字符串)中,如下所示:
onDataAvailable
相反,你想要让你的拉解析器'标记化'' 仅新读取的文本,并为当前读取的数据的任何完全解析部分发出事件(并且不在内存中构建表示从服务器读取的文本的字符串)。
JSON Pull Parser
A'拉解析器'并不是一次解析一个字符串(比如说this.mData += scriptableInputStream.read(aLength);
);而是 你 在您收到的源文本的 每个块 上调用其JSON.parse
方法。解析器负责确定它在输入流中的位置(使用"状态机")以及何时开始或结束读取所谓的原子' (对于JSON,例如:tokenize()
的开头,Array
,Number
的结尾,Array
的开头等),它会调用您提供的回调(或发出一个事件来告诉你它。
所以在你的情况下,假设JSON基本上是Object
Array
的{{1}}。你基本上应该忽略Object
'的开头。然后为Array
'的每个结尾您将单个Object
中的数据写入您的语言环境存储。这样,你一次在内存中获得的最大的东西就是来自你的大文件的单行/元素。
我发现了两个基于JavaScript的JSON Pull Parsers:
您需要将您选择的解析器配置为" listen"在源文本中适当的开头/结尾。
特权JavaScript
由于Object
界面具有特权,如果您仍然希望此网络应用程序主要在网络上运行(并且只有离线模式),则需要实施在Firefox插件中。
此外,由于StreamListener
回调的拉解析器 称为 ,因此它也需要在插件内实现为特权JavaScript。
最简单的方法就是实现bootstrapped(a.k.a"无重启")Firefox插件,然后导出'您需要的功能'您的浏览器窗口,以便您的无特权内容' JavaScript代码可以使用它。
我之前已经两次回答过这个问题(并且涉及相当多的代码):