Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/445.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript HTML5文件阅读器API内存问题_Javascript_Html_Google Chrome_Memory_Filereader - Fatal编程技术网

Javascript HTML5文件阅读器API内存问题

Javascript HTML5文件阅读器API内存问题,javascript,html,google-chrome,memory,filereader,Javascript,Html,Google Chrome,Memory,Filereader,简而言之,我编写了一个文件上传程序,使用HTML5 FileReader API和xhr POST将用户选择的文件上传到服务器。我的客户端代码有几个基本任务,包括从所选文件的标题(这些是DICOM图像文件)中获取值,并在将文件发送到服务器之前显示它们,更新进度条,等等。我还有一些其他功能,包括压缩文件(如果可以加快速度),等等 很快,我发现大文件占用了大量内存(特定于Chrome)。如果有足够大的数据集,Chrome“Aw,Snap!”会完全崩溃。我已经实施了无数的修复:彻底搜索内存泄漏,使用回

简而言之,我编写了一个文件上传程序,使用HTML5 FileReader API和xhr POST将用户选择的文件上传到服务器。我的客户端代码有几个基本任务,包括从所选文件的标题(这些是DICOM图像文件)中获取值,并在将文件发送到服务器之前显示它们,更新进度条,等等。我还有一些其他功能,包括压缩文件(如果可以加快速度),等等

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

,或参阅下文:

HTML:


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();
}
函数片(){
var filesArr=document.getElementById('file').files;
var指数;
对于(索引=0;索引=file.size?file.size:start+chunkSize;
fr.onload=功能(e){
//获取文件内容
var filestream=e.target.result;
如果(++块<块){
控制台信息(块);
loadNext();
}
};
blob=file.slice(开始、结束);
fr.readAsBinaryString(blob);
}
loadNext();
}
我尝试过不同的读取方法(如ArrayBuffer、DataURL)、许多不同的结构(如仅声明1个FileReader和重用等),并尝试过许多不同的块大小进行优化。当我在16个文件中选择~1 GB的特定数据集时,内存使用情况如下所示:

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

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


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

如果有人在这个问题上遇到同样的问题,我想我会分享我们的发现,以缓解这个问题

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

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


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

你可以尝试一次读取一个文件,而不是一次加载所有文件。您也可以尝试创建一个一次性运行时。我一次只创建一个文件-问题仍然存在。我甚至设置了超时,允许在读取每个文件之间有60秒的暂停时间——内存只会每60秒增加一次,而且永远不会减少(正如示例中所示,但显然非常慢)。工人们是一个有趣的想法——我以前从未与他们合作过,我要去看看!谢谢worker有
FileReaderSync()
,这可能会更好,但您始终可以从worker内部调用
self.terminate()
,以停止程序并恢复RAM。您还可以将文件作为blob传递给worker,因此您应该能够像以前一样执行所有操作。
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();
}