HTML5 FileReader API内存问题



简单地说,我已经使用HTML5FileReaderneneneba API和xhrposts编写了一个文件上传器,将用户选择的文件上传到服务器。我的客户端代码有一些基本任务,包括从所选文件的标题中获取值(这些是DICOM图像文件),并在之前显示它们,以将文件发送到服务器,更新进度条等

很快,我注意到大文件占用了的内存(特定于Chrome)。如果有足够大的数据集,Chrome"哇,Snap!"就会完全崩溃。我已经实现了无数的修复:彻底搜索内存泄漏,使用回调和小队列延迟读取和发送文件,一次只读取每个文件的n个大小的块,等等。正如你所能想象的,这导致了一些相当庞大的客户端JavaScript(实际上是coffeescript)。在下面的文章中,我和一位同事将其简化为最基本的内容:以块的形式读取所有选定的文件,并为该二进制数据设置一个变量(让每个人都能阅读解析标题、在必要时压缩并发送每个块的代码)。

https://jsfiddle.net/3nails4you/gsqzrk9g/8/,或参见以下内容:

HTML:

<input id="file" type="file" onchange="slice()" multiple="" />

JavaScript:

function slice() {
    var filesArr = document.getElementById('file').files;
    var index;
    for (index = 0; index < filesArr.length; index++) {
        readFile(filesArr[index]);
    }
}
function readFile(file) {
    var fr = new FileReader(),
        chunkSize = 2097152,
        chunks = Math.ceil(file.size / chunkSize),
        chunk = 0;
    function loadNext() {
        var start, end, blob;
        start = chunk * chunkSize;
        end = start + chunkSize >= file.size ? file.size : start + chunkSize;
        fr.onload = function (e) {
            // get file content
            var filestream = e.target.result;
            if (++chunk < chunks) {
                console.info(chunk);
                loadNext();
            }
        };
        blob = file.slice(start, end);
        fr.readAsBinaryString(blob);
    }
    loadNext();
}

我尝试了不同的读取方法(如ArrayBuffer、DataURL),以及变量范围的许多不同结构(例如,仅声明1个FileReader和重用等),并尝试了许多不同的块大小进行优化。当我在16个文件中选择一个约1GB的特定数据集时,内存使用情况如下所示:

[编辑]我还不能发布图片,所以我只描述一下。查看Windows任务管理器,chrome进程使用了625000K内存。

值得注意的是,如果我等待读取完成(控制台日志将停止输出),内存使用率将变为静态。如果在这一点上,我打开JavaScript控制台,内存使用量就会下降到文件读取开始前的水平。我怀疑打开控制台的行为会引发Chrome的垃圾收集,或者类似的事情,但我不确定。

我发现了一些类似问题的其他问题,但所有这些问题的答案都是假设客户端实际上不需要使用文件的二进制数据。我绝对相信——有什么建议吗?这只是Chromium项目报告的一个bug吗?我的代码中是否有一个明显的错误,我只是错过了?我通常倾向于怀疑后者,但"打开控制台清除内存"这一点仍然让我恼火——如果内存泄漏,真的会是这样吗?感谢您的阅读,我感谢您的建议!

如果有人遇到同样的问题,我想我会分享我们的发现,以缓解这种情况。

我最终购买了一个许可证,并将plupload纳入了我的咖啡脚本中。这有助于以这种方式解决内存问题:

首先,我创建了一个新的plupload对象,并设置了它的事件处理程序(BeforeUpload、UploadProgress等)。它的"Destroy"处理程序调用了一个javascript函数nextUpload(),它创建了另一个上传器对象,并将文件的下一部分排队。破坏发生后,plupload对象的内存使用率被成功回收,因此浏览器的内存使用量保持在合理范围内。

如果有人想读取和上传HTML5文件,我强烈建议探索plupload——它非常容易使用,我们发现Dropbox也在使用它。

最新更新