【问题标题】:File upload in AngularJS causes browser out of memory errorAngularJS中的文件上传导致浏览器内存不足错误
【发布时间】:2018-02-05 00:24:26
【问题描述】:

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

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

我尝试修改发出实际请求的部分并删除了data: JSON.stringify(formattedData),这是第一个瓶颈。结果发现stringifying 在那里是多余的。

但第二个瓶颈仍然存在,它是函数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 方法)

【问题讨论】:

  • 以 json 格式发送文件是个坏主意...使用分段上传(即FormData
  • 使用FormData APIContent-Type: multipart/form-database64 encoding 额外增加了 33% 的开销。如果服务器支持,直接发送文件效率更高。

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


【解决方案1】:

直接从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 并自动设置内容类型。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-12-20
    • 1970-01-01
    • 2011-05-05
    • 1970-01-01
    • 2014-04-15
    • 1970-01-01
    • 1970-01-01
    • 2014-09-21
    相关资源
    最近更新 更多