AS3循环加载JSON仅存储最后迭代数据的问题排查
多JSON文件加载映射错误问题
需求背景
需要从指定对象中加载多个JSON文件,将每个JSON数据对应到特定标识(比如EMOTE对应emote_frames.json,NPC对应npc.json),存入servicesObj以便后续通过标识获取数据。
定义的标识与文件映射关系:
// 键为servicesObj中数据的标识,值为文件名 static var customServices = {EMOTE: "emote_frames", NPC: "npc"};
实现的处理类代码:
class com.customs.Net.CustomServicesManager { var customServices, servicesObj, serviceTypeArr, jsonLoader, serviceLoaderArr, serviceTypes, __get__serviceType, arrServicesToLoad, _loadingServiceType; public function CustomServicesManager() { super(); trace("Loaded Custom Services Manager"); servicesObj = {}; customServices = com.customs.Settings.customServices; } function getServiceData(type) { var _local2 = servicesObj[type]; return (_local2); } public function get serviceType() { serviceTypeArr = []; for(var i in customServices) { serviceTypeArr.push(i); } return (serviceTypeArr); } public function serviceTypeVal(val) { for(var i in customServices) { if(i === val) { return (customServices[i]); } } } public function loadCustomServices() { arrServicesToLoad = this.__get__serviceType(); jsonLoader = new com.cp.util.JSONLoader(); jsonLoader.addEventListener(com.cp.util.JSONLoader.COMPLETE, onCustomServicesJSONLoaded, this); loadOngoingServices(); } public function loadOngoingServices() { if(arrServicesToLoad.length === 0) return (undefined); _loadingServiceType = arrServicesToLoad; for (var i = 0; i < _loadingServiceType.length; ++i) { serviceTypes = _loadingServiceType[i]; jsonLoader.load(serviceTypeVal(serviceTypes) + ".json"); } } public function onCustomServicesJSONLoaded(event) { var _local2 = jsonLoader.data; servicesObj[serviceTypes] = _local2; trace(com.clubpenguin.util.JSONParser.stringify(servicesObj)); trace(servicesObj["NPC"]["130_npc"].uniqueId); } }
问题现象
预期servicesObj中EMOTE和NPC分别对应各自的JSON数据,但实际只有最后加载的NPC数据正确,EMOTE的数据被错误存入NPC键下,无法通过EMOTE标识获取。
输出的servicesObj内容:
{"NPC":[{"disabled":true,"emote_name":"Laughing Face","frame_menu_id":1,"frame_balloon_id":1},{"emote_name":"Smiley","frame_menu_id":2,"frame_balloon_id":2},{"emote_name":"Coffee Cup","frame_menu_id":3,"frame_balloon_id":13},{"emote_name":"Straight Face","frame_menu_id":4,"frame_balloon_id":3},{"emote_name":"Frown","frame_menu_id":5,"frame_balloon_id":4},{"emote_name":"Game","frame_menu_id":6,"frame_balloon_id":18},{"emote_name":"Surprise","frame_menu_id":7,"frame_balloon_id":5},{"emote_name":"Sticking Out Tongue","frame_menu_id":8,"frame_balloon_id":6},{"emote_name":"Popcorn","frame_menu_id":9,"frame_balloon_id":29},{"emote_name":"Wink","frame_menu_id":10,"frame_balloon_id":7},{"emote_name":"Green Sickly Face","frame_menu_id":11,"frame_balloon_id":8},{"emote_name":"Pizza","frame_menu_id":12,"frame_balloon_id":24},{"disabled":true,"emote_name":"Red Angry Face","frame_menu_id":13,"frame_balloon_id":9},{"emote_name":"Sad Face","frame_menu_id":14,"frame_balloon_id":10},{"emote_name":"Ice Cream","frame_menu_id":15,"frame_balloon_id":26},{"emote_name":"Meh Face","frame_menu_id":16,"frame_balloon_id":11},{"emote_name":"Cake","frame_menu_id":17,"frame_balloon_id":28},{"emote_name":"Clover","frame_menu_id":18,"frame_balloon_id":17},{"emote_name":"Heart","frame_menu_id":19,"frame_balloon_id":30},{"emote_name":"Lightbulb","frame_menu_id":20,"frame_balloon_id":12},{"emote_name":"Flower","frame_menu_id":21,"frame_balloon_id":16},{"emote_name":"Skull","frame_menu_id":22,"frame_balloon_id":40},{"emote_name":"Shocked Face","frame_menu_id":23,"frame_balloon_id":41},{"emote_name":"The Nigger","frame_menu_id":24,"frame_balloon_id":42},{"emote_name":"Pink Flower","frame_menu_id":25,"frame_balloon_id":43}]} {"NPC":{"130_npc":{"isEnabled":true,"itemsObj":{"total_membership_days":0,"is_member":1,"frame":0,"y_corr":100,"x_corr":100,"photo_id":0,"flag_id":0,"feet":0,"hand":0,"body":0,"neck":0,"face":0,"head":0,"colour_id":0},"bitmask":1,"username":"[NPC] Pelican","uniqueId":9000251},"100_npc":{"isEnabled":true,"itemsObj":{"total_membership_days":0,"is_member":1,"frame":0,"y_corr":256,"x_corr":467,"photo_id":0,"flag_id":0,"feet":0,"hand":0,"body":467,"neck":256,"face":26,"head":0,"colour_id":8},"bitmask":1,"username":"[NPC] Bob","uniqueId":9000234}}}
第一部分为EMOTE的正确数据,但被错误存入NPC键下;第二部分NPC数据正确。
问题原因
- 单一Loader实例重复使用:循环中用同一个
JSONLoader加载多个文件,后一次加载会覆盖前一次的请求状态,导致无法区分回调对应哪个标识。 - 变量覆盖问题:循环结束后
serviceTypes最终值为NPC,两个请求完成时都会用这个值作为键存入servicesObj,导致EMOTE数据被覆盖到NPC键下。
解决方案
方案1:为每个请求创建独立Loader实例
修改loadOngoingServices和回调方法,为每个请求创建新的JSONLoader,并绑定对应的服务标识:
public function loadOngoingServices() { if(arrServicesToLoad.length === 0) return; _loadingServiceType = arrServicesToLoad; for (var i = 0; i < _loadingServiceType.length; ++i) { var serviceType = _loadingServiceType[i]; var loader = new com.cp.util.JSONLoader(); loader.serviceType = serviceType; // 将标识绑定到Loader实例 loader.addEventListener(com.cp.util.JSONLoader.COMPLETE, onCustomServicesJSONLoaded, this); loader.load(serviceTypeVal(serviceType) + ".json"); } } public function onCustomServicesJSONLoaded(event) { var loader = event.target as com.cp.util.JSONLoader; var data = loader.data; var serviceType = loader.serviceType; servicesObj[serviceType] = data; trace(com.clubpenguin.util.JSONParser.stringify(servicesObj)); // 检查是否所有服务都加载完成 var allLoaded = true; for(var type in customServices) { if(!servicesObj[type]) { allLoaded = false; break; } } if(allLoaded) { trace("所有自定义服务加载完成"); // 此处可添加加载完成后的逻辑 } }
方案2:用闭包保存循环标识(不推荐,不如多实例直观)
如果不想创建多个Loader实例,可在循环中用闭包捕获当前标识,确保回调能拿到正确值:
public function loadOngoingServices() { if(arrServicesToLoad.length === 0) return; _loadingServiceType = arrServicesToLoad; for (var i = 0; i < _loadingServiceType.length; ++i) { var serviceType = _loadingServiceType[i]; // 闭包捕获当前循环的serviceType (function(currentType) { var tempLoader = new com.cp.util.JSONLoader(); tempLoader.addEventListener(com.cp.util.JSONLoader.COMPLETE, function(event) { var data = tempLoader.data; servicesObj[currentType] = data; trace(com.clubpenguin.util.JSONParser.stringify(servicesObj)); // 检查全量加载完成 var allLoaded = true; for(var type in customServices) { if(!servicesObj[type]) { allLoaded = false; break; } } if(allLoaded) { trace("所有自定义服务加载完成"); } }, this); tempLoader.load(serviceTypeVal(currentType) + ".json"); })(serviceType); } }
核心优化点
- 每个请求绑定专属标识,避免回调时键名错误
- 确保每个请求状态独立,不被后续请求覆盖
- 添加全量加载完成检查,方便触发后续业务逻辑
内容的提问来源于stack exchange,提问作者Zesty
相关产品推荐
相关产品推荐

