Node/Express解析JSON空数组返回字符串问题求助
最近在Node/Express项目里踩了个坑,折腾了好一会儿才搞定,跟大家唠唠整个过程:
问题现象
我有个JSON文件,初始内容是"[]"(也就是已经被JSON.stringify处理过的空数组)。用fs.readFileSync读取文件内容后,调用JSON.parse解析并赋值给parsedObjs变量。本来预期得到的是空数组,但实际用console.log(typeof parsedObjs)查看时,结果居然是string!
更奇怪的是,我在浏览器控制台里测试JSON.parse("[]"),明明能正常得到空数组,但放到Node/Express环境里就完全不对。
后来我试着把JSON文件的内容改成未字符串化的[],这次解析后确实得到了数组,但每次运行都会触发这个错误:
Unexpected end of JSON input
排查与解决
折腾了半天,终于找到问题的根源——我的代码里同时存在异步的fs.writeFile操作和读取操作,两个操作在同一时间访问这个JSON文件,导致读取到的内容要么是不完整的,要么是被异步写入干扰后的错误格式。
当我把异步的writeFile改成同步的writeFileSync之后,所有问题都消失了:读取解析后的parsedObjs类型正确是object(也就是空数组),也不会再报JSON结束异常的错误。
举个例子,之前的异步写入代码是这样的:
fs.writeFile('./data.json', JSON.stringify([]), (err) => { if (err) throw err; });
改成同步写入后:
fs.writeFileSync('./data.json', JSON.stringify([]));
对应的读取函数也能正常工作了:
const getObjs = () => { const data = fs.readFileSync('./data.json', 'utf8'); const parsedObjs = JSON.parse(data); console.log(typeof parsedObjs); // 现在输出object return parsedObjs; };
本质上是因为异步写入和同步读取之间没有做好时序控制,导致文件读写冲突,拿到了错误的文件内容去解析。改用同步写入后,确保了写入操作完成后再进行读取,避免了竞态条件。
内容的提问来源于stack exchange,提问作者Cuckoo

