【问题标题】:Javascript how to load contents from multiple json files using FileReader.onload?Javascript 如何使用 FileReader.onload 从多个 json 文件中加载内容?
【发布时间】:2019-12-03 19:05:06
【问题描述】:

我需要上传多个 json 文件并将它们的内容存储在一个数组中。我的目标是以某种方式将它们合并在一起。我试过这样做:

var results = new Array();    //global variable

document.getElementById('uploadId').onclick = function () {
   var files = document.getElementById('selectFiles').files;

   for (var i = 0; i < files.length; i++) {
       var fr = new FileReader();

       fr.onload = function (e) {
           console.log(e);
           var result = JSON.parse(e.target.result);
           results.push(result);
       }

       fr.readAsText(files.item(i));
   }
   process();
}; 

function process(){
   console.log(results); // displays everything as expected
   console.log(results.length); // returns 0 ?!
   console.log(results[0]) // return undefined ?!
}

然后在将results 数组记录到控制台时,一切都按预期显示。但是当我尝试遍历数组时,所有单个对象都是undefinedresults.length 也返回 0

我猜可能存在与异步性有关的问题。知道如何解决这个问题吗?

【问题讨论】:

  • 当它被记录时,results 旁边是否恰好有一个蓝色的“i”符号?
  • @matthew-e-brown 是的,确实如此
  • 那个小小的 'i' 是浏览器的控制台,它告诉您,当您在控制台中查看该数据时,该数据已被评估,而当它的行时 not达到了。这意味着(可能)在 process() 运行时它是空的,直到之后您检查它才真正被填充。
  • @matthew-e-brown 所以在调用 process() 之前我需要稍等片刻,直到添加到数组完成?
  • 您需要在所有fr.onload() 完成后执行process()

标签: javascript json filereader onload


【解决方案1】:

您可以将预定义的对象绑定到存储两个值的加载函数(或定义范围和/或全局变量):filesToProcess 和 filesProcessed。在每次加载时,您都会递增 filesProcessed,直到它到达 filesToProcess。也就是说,如果您想保留 IE 等旧浏览器或旧 Safari 版本的支持。

遗憾的是,我只能在理论上展示它,没有任何实际测试。

document.getElementById('uploadId').onclick = function () {
   var files = document.getElementById('selectFiles').files,
       param = {filesProcessed: 0, filesToProcess: files.length};

   for (var i = 0; i < files.length; i++) {
       var fr = new FileReader();

       fr.onload = function(e){
           results.push(JSON.parse(e.target.result));

           //REM: this being param
           this.filesProcessed++;

           if(this.filesProcessed === this.filesToProcess){
               process()
           }
       }.bind(param)

       fr.readAsText(files.item(i));
   }
};

【讨论】:

    【解决方案2】:

    通常,您可以通过将您正在等待文件的代码(在本例中为process)作为FileReader 的侦听器的一部分来避免此问题,以便在完成后发生。当您需要让用户将多个文件上传到同一个 input 并且无法单独处理它们时,我想不出这样的场景(即,如果您需要两个文件同时进行,请采取它们在单独的inputs 中并使用提交按钮)。

    但是,如果您这样做,我的建议是使用 async/await 或 ES6 Promises。这是我将所有文件作为 JSON 读取到数组中的方法,然后然后对它们做一些事情。

    const results = [];
    const input = document.querySelector('input[type="file"]');
    
    input.addEventListener('change', async() => {
      await Promise.all([...input.files].map(file => new Promise((resolve, reject) => {
        const reader = new FileReader();
        reader.onloadend = () => {
          try {
            resolve(results.push(JSON.parse(reader.result)));
          } catch (err) {
            // Return a blank value; ignore non-JSON (or do whatever else)
            console.log('Please use .json!');
            resolve();
          }
        }
        reader.readAsText(file);
      })));
    
      // Do Stuff
      console.log(results);
      console.log(results.length);
      console.log(results[0]);
    });
    <form action="#">
      <input type="file" multiple />
    </form>

    这与我的answer here 非常相似。

    要测试的一些 JSON 文件:

    [
      {
        "name": "bobby",
        "age": 12
      },
      {
        "name": "don",
        "age": 64
      },
      {
        "name": "dale",
        "age": 16
      },
      {
        "name": "toby",
        "age": 52
      },
      {
        "name": "alfred",
        "age": 234
      },{
        "name": "steve",
        "age": 12
      }
    ]
    
    [
      {
        "name": "denmark"
      },
      {
        "name": "sweden"
      },
      {
        "name": "norway"
      },
      {
        "name": "finland"
      }
    ]
    

    【讨论】:

    • @pelikann 请记住,在使用 Promises / Async & Await 时,您会失去 IE 支持。如果它解决了您的问题,请不要忘记选择已接受的答案! :)
    • 我也想到了一个蹩脚的解决方案。我可以将 process() 包装成 5s 之类的 setTimeout,我想它在大多数情况下都可以工作。
    • @pelikann 你当然可以,但我认为说大多数人会不赞成这样的解决方案是轻描淡写;)
    猜你喜欢
    • 2020-11-25
    • 2010-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多