合并多JSON文件数据到单个对象时仅获最后24条数据的问题排查
问题描述
我在pl文件夹中有31个JSON文件,命名为objects_p=1、objects_p=2等。除最后一个文件包含24个值外,其余每个文件都包含50个值。我尝试将所有数据整合到一个对象中,代码如下:
let sourceObj={}; for (let i=1;i<32;i++){ fetch(`pl/objects_p=${i}`) .then((response) => response.json()) .then((data) => { let new_obj = Object.assign(sourceObj,data); sourceObj = new_obj }); }
本质上我是想在循环中把数据追加到对象里,但console.log输出sourceObj时,只得到最后24个值,而非预期的1524个。请问错误出在哪里?
问题分析与解决方法
核心错误点
- 异步竞态问题:
fetch是异步请求,循环会快速发起所有31个请求,但响应返回的顺序不确定,sourceObj的赋值会被多个异步回调打乱。 - 键名覆盖逻辑:
Object.assign会用源对象的键值覆盖目标对象的同名键。如果所有JSON文件的键名完全重复,最后返回的请求(刚好是第31个)会把之前所有键值全部覆盖,最终只剩24个值。 - 可能的过早打印:如果在循环结束后立刻打印
sourceObj,此时大部分请求还未完成,也会导致结果不完整,但你提到的最终只看到24个值,核心原因还是键名覆盖。
解决方法
方案1:用数组存储所有数据(适合键名重复的场景)
先收集所有请求的Promise,用Promise.all等待全部完成后,将所有数据合并为数组:
// 收集所有fetch请求的Promise const fetchTasks = []; for (let i = 1; i < 32; i++) { fetchTasks.push(fetch(`pl/objects_p=${i}`).then(res => res.json())); } // 等待所有请求完成后处理结果 Promise.all(fetchTasks) .then(allData => { // 把所有对象的值提取出来合并成一个数组 const combinedData = allData.flatMap(item => Object.values(item)); console.log(combinedData.length); // 预期为1524 }) .catch(error => console.error('请求失败:', error));
方案2:给键名加前缀后合并到对象(需保留原键名并区分来源)
给每个文件的键名加上来源标识前缀,避免覆盖,再合并到对象:
const fetchTasks = []; for (let i = 1; i < 32; i++) { fetchTasks.push( fetch(`pl/objects_p=${i}`) .then(res => res.json()) .then(data => { // 为每个键添加前缀,区分来自哪个文件 const prefixedData = {}; Object.keys(data).forEach(key => { prefixedData[`p${i}_${key}`] = data[key]; }); return prefixedData; }) ); } Promise.all(fetchTasks) .then(allPrefixedData => { // 合并所有带前缀的对象 const sourceObj = Object.assign({}, ...allPrefixedData); console.log(Object.keys(sourceObj).length); // 预期为1524 }) .catch(error => console.error('请求失败:', error));
内容的提问来源于stack exchange,提问作者user2869150
相关产品推荐
相关产品推荐

