JSON.stringify处理嵌套对象数组失效,返回空数组问题求助
JSON.stringify序列化时嵌套数组返回空数组的问题
我知道这个问题有人问过,但现有方案都无效,无法定位问题。我有一个包含嵌套对象数组的对象,使用JSON.stringify序列化时,嵌套数组返回空数组。
以下是构建对象的简化版本(原代码通过循环遍历行,此处手动创建两行):
// JAVASCRIPT let obj = {}; obj['type'] = 'Setting'; obj['id'] = 1; obj['import'] = parseCSV(); function parseCSV() { let jsonData = []; let row1 = {}; let row2 = {}; row1['date'] = '2022-01-01'; row1['amount'] = '30'; row2['date'] = '2022-01-02'; row2['amount'] = '50'; jsonData.push(row1); jsonData.push(row2); return jsonData; } console.log('RAW DATA', obj); console.log('STRINGIFIED', JSON.stringify(obj));
该简化版本能输出正确的序列化JSON。
但完整版本中,import字段序列化后是空数组。问题出在parseCSV函数中,以下是完整的parseCSV函数:
function parseCSV(file) { let filename = file.name; let extension = filename.substring(filename.lastIndexOf('.')).toUpperCase(); if(extension == '.CSV') { try { let reader = new FileReader(); let jsonData = []; let headers = []; reader.readAsBinaryString(file); reader.onload = function(e) { let rows = e.target.result.split('\n'); for(let i = 0; i < rows.length; i++) { let cells = rows[i].split(','); let rowData = {}; for(let j = 0; j < cells.length; j++) { if(i == 0) headers.push(cells[j].trim()); else { if(headers[j]) rowData[headers[j]] = cells[j].trim(); } } if(i != 0 && rowData['date'] != '') jsonData.push(rowData); } } return jsonData; } catch(err) { console.error('!! ERROR READING CSV FILE', err); } } else alert('PLEASE UPLOAD A VALID CSV FILE'); }
编辑:按照@BJRINT的建议在parseCSV前添加await时,出现语法错误await is only valid in async function,相关代码如下:
async function submitForm(event) { event.preventDefault(); let newItem = await gatherFormData(event.target); return fetch('server.php', { method: "POST", headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, body: JSON.stringify(newItem) }) .then(checkError) .then(data => parseData(data)) .catch(err => console.error('>> ERROR READING JSON DATA', err)); } function gatherFormData(target) { const inputs = target.querySelectorAll('input'); let obj = {}; inputs.forEach(function(input) { if(intKeys.indexOf(input.name) >= 0) obj[input.name] = parseInt(input.value); else if(curKeys.indexOf(input.name) >= 0) obj[input.name] = parseInt(parseFloat(input.value) * 100); else if(chkKeys.indexOf(input.name) >= 0) input.checked ? obj[input.name] = 1 : obj[input.name] = 0; else if(fileKeys.indexOf(input.name) >= 0 && input.files.length > 0) obj[input.name] = parseCSV(input.files[0]); else obj[input.name] = input.value; }); return obj; }
问题原因及解决方案
问题根源
FileReader是异步操作,你的parseCSV函数在reader.onload回调执行前就返回了空的jsonData数组。等文件读取完成并填充数据时,函数早已返回,所以最终序列化的是空数组。
修复步骤
- 将
parseCSV改为返回Promise,在文件读取完成并处理好数据后再返回结果; - 将
gatherFormData改为异步函数,调用parseCSV时使用await等待结果; - 由于
forEach不支持异步等待,将遍历逻辑改为for...of循环。
修改后的代码
修正后的parseCSV函数
function parseCSV(file) { return new Promise((resolve, reject) => { let filename = file.name; let extension = filename.substring(filename.lastIndexOf('.')).toUpperCase(); if (extension === '.CSV') { try { const reader = new FileReader(); let jsonData = []; let headers = []; reader.onload = function(e) { const rows = e.target.result.split('\n'); for (let i = 0; i < rows.length; i++) { const cells = rows[i].split(','); const rowData = {}; for (let j = 0; j < cells.length; j++) { if (i === 0) { headers.push(cells[j].trim()); } else { if (headers[j]) { rowData[headers[j]] = cells[j].trim(); } } } if (i !== 0 && rowData['date'] !== '') { jsonData.push(rowData); } } resolve(jsonData); }; reader.onerror = function(err) { console.error('!! ERROR READING CSV FILE', err); reject(err); }; reader.readAsBinaryString(file); } catch (err) { console.error('!! ERROR READING CSV FILE', err); reject(err); } } else { const errorMsg = 'PLEASE UPLOAD A VALID CSV FILE'; alert(errorMsg); reject(new Error(errorMsg)); } }); }
修正后的gatherFormData函数
async function gatherFormData(target) { const inputs = target.querySelectorAll('input'); let obj = {}; // 使用for...of支持await for (const input of inputs) { if (intKeys.indexOf(input.name) >= 0) { obj[input.name] = parseInt(input.value); } else if (curKeys.indexOf(input.name) >= 0) { obj[input.name] = parseInt(parseFloat(input.value) * 100); } else if (chkKeys.indexOf(input.name) >= 0) { obj[input.name] = input.checked ? 1 : 0; } else if (fileKeys.indexOf(input.name) >= 0 && input.files.length > 0) { // await等待parseCSV完成 obj[input.name] = await parseCSV(input.files[0]); } else { obj[input.name] = input.value; } } return obj; }
这样修改后,gatherFormData会等待CSV文件读取并解析完成后再返回对象,JSON.stringify就能正确序列化包含数据的嵌套数组了。
内容的提问来源于stack exchange,提问作者oscarale
相关产品推荐
相关产品推荐

