JavaScript多JSON文件对比:全局变量无法访问问题求助
解决FileReader异步读取多JSON文件后无法正确访问全局数据的问题
兄弟,你完全戳中了JavaScript异步操作的痛点!你猜的没错,问题根源就是异步时序不对,再加上浏览器控制台的一个小特性,才让你出现“控制台能显示对象但展开不了、代码里访问属性是undefined”的诡异情况。
为啥会这样?
首先,FileReader的readAsBinaryString和onload是异步执行的——也就是说,当你调用readFile(0)之后,代码不会傻等着文件读完才往下走,而是立刻执行后面的console.log(data)和return data,这时候data还是个空对象,半毛钱数据都没塞进去。
至于Firefox控制台能显示对象但点不开的情况,是浏览器的惰性渲染机制在搞鬼:它打印的是data对象的引用,你刚打印的时候它确实是空的,但等你点击展开时,异步的文件读取已经完成,data已经被填充了数据,所以能看到内容,但代码里直接访问属性的时机早了一步,自然拿不到值。
另外还有个小问题:你复用了同一个FileReader实例读取多个文件,虽然当前代码逻辑是等前一个读完再读下一个,但这种写法有潜在冲突风险,最好每个文件用单独的reader实例。
怎么解决?
这里给你两种实用的修改方案,看你习惯哪种:
方案一:用Promise+async/await重构(推荐,代码更清晰)
把单文件读取包装成Promise,用异步语法确保所有文件读完后再处理数据:
var data = {}; // 把单个文件读取包装成Promise function readSingleFile(file) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = (e) => { try { const bin = JSON.parse(e.target.result); resolve(bin); } catch (err) { reject(err); } }; reader.onerror = reject; reader.readAsBinaryString(file); }); } async function readmultifiles(files) { // 依次读取每个文件(如果想并行读取可以用Promise.all,看你的需求) for (const file of files) { const bin = await readSingleFile(file); for (const task in bin['values']) { addData(bin['info']['date'], task, bin['values'][task]); } } console.log("所有文件读取完成"); console.log(data); return data; } function addData(date, task, value) { if (!data[task]) { data[task] = {}; } data[task][date] = value; } const fileInput = document.querySelector('#file'); fileInput.addEventListener('change', async function() { console.log(fileInput); const files = fileInput.files; // 等待所有文件读取完成再处理数据 await readmultifiles(files); console.log("index"); console.log(data); console.log(data['task_1']); // 现在就能正常访问啦 });
方案二:用回调函数(适合不支持async/await的旧环境)
如果不想用现代异步语法,也可以用回调函数来通知数据加载完成:
var data = {}; function readmultifiles(files, callback) { let index = 0; function readFile() { if( index >= files.length ) { console.log("所有文件读取完成"); console.log(data); callback(data); // 全部读完后调用回调,把数据传出去 return; } const file = files[index]; // 每个文件用单独的FileReader实例,避免复用冲突 const reader = new FileReader(); reader.onload = function(e) { const bin = JSON.parse(e.target.result); for(const task in bin['values']){ addData(bin['info']['date'], task, bin['values'][task]); } index++; readFile(); } reader.readAsBinaryString(file); } readFile(); } function addData(date, task, value){ if(!data[task]){ data[task] = {}; } data[task][date] = value; } const fileInput = document.querySelector('#file'); fileInput.addEventListener('change', function() { console.log(fileInput); const files = fileInput.files; // 传入回调函数,等数据加载完再处理 readmultifiles(files, function(loadedData) { console.log("index"); console.log(loadedData); console.log(loadedData['task_1']); // 这里就能拿到正确的值了 }); });
内容的提问来源于stack exchange,提问作者Dams
相关产品推荐
相关产品推荐

