AngularJS中的文件上传导致浏览器内存不足错误

时间:2017-08-27 16:27:58

标签: javascript angularjs file-upload out-of-memory

我有一个AngularJS代码来执行文件上传。起初我认为它工作正常但是当我尝试上传更大的文件(例如5个文件,每个10 MB)时,我发现这个代码在内存处理方面表现很差。

例如:当我附加5个文件(每个10 MB =总共50 MB)时,峰值浏览器进程内存需求达到2 GB! 我已经在Firefox,Chrome和IE中对它进行了测试。此外,在浏览器进程达到3 GB内存时Chrome中,页面崩溃。 在Firefox中,我可以在尝试一次上传超过80 MB时在控制台中看到错误: out of memory

我试图修改实际请求所在的部分data: JSON.stringify(formattedData),这是第一个瓶颈。事实证明stringify在那里是多余的。

但是第二个瓶颈仍然存在,即函数binArrayToJson,它接受​​ArrayBuffer并将数据读入字节数组。

var binArrayToJson = function (binArray) {
   var str = [binArray.length];
   for (var i = 0, binLength = binArray.length; i < binLength; i++) {
   str[i] = binArray[i];
   }
   return str;
}

var applyAttachments = function (data1) {
   angular.forEach(data1,
       function (value, key) {
           if (key === "Attachments") {
               for (var i = 0; i < value.length; i++) {
                   if (value[i].file) { //already saved item don't contain 'file' property
                       var reader = new FileReader();

                       reader.onloadend = (function (f) {
                           return function (result) {

                               var arrayBuffer = result.target.result;
                               value[f].fileContent = binArrayToJson(new Uint8Array(arrayBuffer));
                               value[f].isUploaded = true;
                           };
                       })(i);

                       reader.readAsArrayBuffer(value[i].file);
                   }
               }
           }
       });
};


var createMVCModel = function (output) {
   var defaultStringValue = "";
   return {
       id: output.id,
       Name: output.name || defaultStringValue,
       Status: output.status || "Draft",
       Date: output.date || null
       Attachments: output.attachments || []
   };
};

var saveModel = function (data, url) {
   var formattedData = createMVCModel(data);
   var deferred = $q.defer();

   applyAttachments(formattedData);

   var check = function () {
       if (allNewFilesUploaded(formattedData) === true) {
           $http({
                   url: url,
                   method: "POST",
                   data: formattedData,
                   headers: { 'Content-Type': undefined }
               })
               .then(function (result) {
                       deferred.resolve(result);
                   },
                   function (result) {
                       deferred.reject(result);
                   });
       } else {
           setTimeout(check, 1000);
       }

   }
   check();
   return deferred.promise;
};

我省略了满足以下要求的部分:

  • 检查文件数量(限制为10)
  • 检查每个文件的大小(限制为每个10 MB)
  • 检查允许的文件扩展名
  • 将其余的(文本)数据与文件一起发送到服务器(ASP.NET MVC方法)

1 个答案:

答案 0 :(得分:0)

直接从FileList

执行多个$http.post请求

为避免内存问题,直接发送文件:

$scope.upload = function(url, fileList) {
    var config = { headers: { 'Content-Type': undefined },
                   transformResponse: angular.identity
                 };
    var promises = fileList.map(function(file,index) {
        config.params = {'n': index, 'name': file.name};
        return $http.post(url, file, config);
    });
    return $q.all(promises);
};

发送带有File object的POST时,设置'Content-Type': undefined非常重要。然后,XHR send method会检测File object并自动设置内容类型。