【问题标题】:use xhr.onprogress to process large ajax download without running out of memory?使用 xhr.onprogress 处理大型 ajax 下载而不会耗尽内存?
【发布时间】:2013-12-02 05:25:37
【问题描述】:

假设我的公司提供一个大型日志文件 (4+ GB),其中最新的日志位于顶部。我想建立一个网页来搜索该文件中的关键字“Mike”。带宽不受限制,但此网页只能是静态文件(即没有服务器端功能)。

示例日志文件:

Joe completed Task 1234 on 2013-10-10
Joe completed Task 1235 on 2013-10-11
Mike completed Task 1236 on 2013-10-11
Joe completed Task 1237 on 2013-10-13
...

显然,我无法将整个文件放入浏览器的内存中,所以我试图找到一种方法来请求文件,在下载数据时搜索数据,然后丢弃不相关的数据以保存记忆。我正在使用xhr.onprogress 事件通过xhr.responseText 获取部分下载的日志文件并进行搜索,但在阅读完responseText 后我无法重置它。

到目前为止,这是我的算法:

var xhr = new XMLHttpRequest();
xhr.onprogress = function(e){
    var cur_len = xhr.responseText.length;
    var found_mike = xhr.responseText.indexOf("Mike") != -1 ? true : false;
    xhr.responseText = ""; //clear responseText to save memory
    console.log("%d - %s - %d", cur_len, found_mike, xhr.responseText.length);
};
xhr.open("get", "mylogfile.txt", true);
xhr.send();

我希望控制台会显示类似 234343 - false - 0 的内容,但我得到的是 234343 - false - 234343,并且浏览器内存不足(因为未清除 responseText)。

有没有一种方法可以丢弃 responseText,以便浏览器可以下载和处理文件,而无需将整个文件保存在内存中?

编辑:另外,如果 responseText 是只读的,为什么它不抛出错误/警告?

【问题讨论】:

标签: javascript ajax html xmlhttprequest


【解决方案1】:

问了一个朋友,他有一个很好的答案:Range headers (stackoverflow question, jsfiddle)

var chunk_size = 100000; //100kb chunks
var regexp = /Mike/g;
var mikes = [];
function next_chunk(pos, file_len){
    if(pos > file_len){
        return;
    }
    var chunk_end = pos + chunk_size < file_len ? pos + chunk_size : file_len;
    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function(){
        if(xhr.readyState == 4 && xhr.status == 206){
            //push mikes to result
            while ((match = regexp.exec(xhr.responseText)) != null) {
                mikes.push(pos + match.index);
            }
            //request next chunk
            file_len = parseInt(xhr.getResponseHeader("Content-Range").split("/")[1]);
            next_chunk(chunk_end + 1, file_len);
        }
    };
    xhr.open("get", "mylogfile.txt", true);
    xhr.setRequestHeader("Range", "bytes=" + pos + "-" + chunk_end);
    xhr.send();
}
next_chunk(0, chunk_size);

【讨论】:

  • 如果你想要更好的性能,你可能应该远离 base 10,如果你只想搜索字符串,我建议的块大小是 134217728 字节块=128Mb 块,或者 32Mb=33554432 字节块如果您想做更高级的 CPU 密集型操作。我之所以会建议这么小的限制,是因为 IE 确实是一个相当大的内存消耗者。
  • 这是一种可行的方法。但是请记住,您需要服务器通过 Accept-Ranges: &lt;unit&gt; 来允许请求范围。 mdn
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-10-17
  • 2021-02-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-20
  • 1970-01-01
相关资源
最近更新 更多