FileReader 在循环中加载并赋值?

FileReader onload and assign value in loop?

我在获取文件 reader 内容分配时遇到困难。无论如何要等待文件 reader 完成加载并在将文件内容推送到数组之前分配文件内容?

我有一个输入文件类型按钮列表如下:

@for (int i = 0; i < @Model.LetterList.Count(); i++)
{
  <tr>
     <td>
         <input type="file" id="LetterAttachment" name="LetterAttachment" accept="application/pdf">
     </td>
  </tr>
}

当我点击提交时,我想循环将文件内容值分配到我的表单列表中,下面是我的 javascript 代码:

var attach=""; // empty variable for assign file content
function ApproverAction(action) {

        var formList = [];

        $("input[name='LetterAttachment']").each(function () {

            if (this.files && this.files[0]) {

                // I perform file reader here to assign the file content into attach....
                var FR = new FileReader();
                FR.onload = function (e) {
                    attach = e.target.result;
                }    
                FR.readAsDataURL(this.files[0]);

                 var form = {
                        ID: newGuid(),
                        FileContents: attach, <<< ---- However it showing empty 
                        DocumentName: this.files[0].name,
                        DocumentSize: this.files[0].size,
                        DocumentContentType: 'application/pdf',
                        SourceType: 'OnlineAssessment',
                        CreatedDate: '@DateTime.Now'
                }

                formList.push(form);
            }

        });

        console.log(formList);
}

但是我无法完全正确地得到输出结果:

非常感谢任何帮助和提示!谢谢!

这是因为您在 FR.onload 中提供的函数是异步执行的。因此,它之后的代码将在调用函数之前执行,因此 JSON 中的 FileContents 的值为空。

您可以做的是在函数内完成所有您想做的事情,或者使用其他函数,例如 readAsText

...
                var FR = new FileReader();
                FR.readAsDataURL(this.files[0]);

                 var form = {
                        ID: newGuid(),
                        FileContents: FR.readAsText(this.files[0),
                        DocumentName: this.files[0].name,
                        DocumentSize: this.files[0].size,
                        DocumentContentType: 'application/pdf',
                        SourceType: 'OnlineAssessment',
                        CreatedDate: '@DateTime.Now'
                }
...

参考这个例子 onLoad and readAsText

对在 onload 函数中解析的每个文件使用一个承诺,并将这些承诺推送到一个数组中

然后在所有承诺都已解决后使用 Promise.all() 发送数据。请注意,错误处理将需要根据您想要的流程进行改进

function ApproverAction(action) {

  var filePromises = [];

  $("input[name='LetterAttachment']").each(function() {

      if (this.files && this.files[0]) {

         // reference to this to use inside onload function
         var _input = this;

        var promise = new Promise(function(resolve, reject) {

            var FR = new FileReader();               

            FR.onload = function(e) {    
              var form = {
                ID: newGuid(),
                FileContents: e.target.result;,
                DocumentName: _input.files[0].name,
                DocumentSize: _input.files[0].size,
                DocumentContentType: 'application/pdf',
                SourceType: 'OnlineAssessment',
                CreatedDate: '@DateTime.Now'
              }    

              // resolve promise with object
              resolve(form);
            }
            FR.readAsDataURL(this.files[0]);

            if(FB.error){
              //   needs more robust error handling, for now just reject promise
              reject(FB.error)
            }
            // push promise to array
            filePromises.push(promise)
          }

        });         
    }

  });
  // return a new promise with all the data
  return Promise.all(filePromises)
     
}

使用函数返回的 promise

ApproverAction(action).then(function(formList){
      // do something with the data array
      console.log(formList);         
      
}).catch(function(err){
      console.error("Ooops something went wrong')
});