【问题标题】:FileReader onload and assign value in loop?FileReader onload 并在循环中赋值?
【发布时间】:2020-10-25 02:55:33
【问题描述】:

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

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

@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);
}

但是我不能完全正确地得到输出结果:

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

【问题讨论】:

    标签: javascript c# jquery asp.net-mvc asp.net-mvc-5


    【解决方案1】:

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

    然后在所有承诺解决后使用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')
    });
    

    【讨论】:

    • 感谢您的反馈,目前我正在尝试您的解决方案,但 _input.files[0].name 和大小出现错误,因为它显示“未捕获的类型错误:无法读取未定义的属性 '0' ”。我可以知道为什么吗?
    • 哦。我犯了一个愚蠢的错误。移动var _input = this; 上方新的承诺!查看答案中的更新
    • 非常感谢!虽然我没有完全使用代码,但我已经掌握了概念并参考它!将其标记为答案!祝你有美好的一天!
    • hmm 我发现它返回未定义的数组列表,你知道吗?
    • 如果没有一个可以重现它的演示,那就不是真的了。可以将一个放在 jsfiddle 或其他沙盒站点中,可能很快就会失败
    【解决方案2】:

    这是因为您在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'
                    }
    ...
    

    请参阅此示例了解onLoadreadAsText

    【讨论】:

    • 您也可以通过 charlietfl 的代码。正如我在回答中提到的那样,这就是您如何对函数本身的值执行所有您想要执行的操作(*您可以做的是在函数中执行您想要执行的所有操作 *)
    • 感谢您的反馈!这也给了我一些见解:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-25
    • 1970-01-01
    • 2013-09-17
    相关资源
    最近更新 更多