Pathfinder API数据获取后console.log重复输出问题求助
问题分析与解决方案
核心问题原因
循环代码的重复请求根源:你最初的循环实现里,在
pflibraries.forEach的每一次迭代中,先把当前子endpoint推到pathfinderLibraries数组,紧接着就遍历整个数组发起请求。比如第一个元素被添加后,数组长度为1,发起1次请求;第二个元素添加后,数组长度为2,发起2次请求(包含第一次的元素),以此类推,最终每个子endpoint会被请求N次(N是它在数组中的位置+1),自然console.log会重复输出。手动请求的残留重复:大概率是
getData()函数被多次触发执行了——比如页面加载时重复调用,或者绑定了重复的事件监听器导致函数多次运行。
修复后的批量实现代码
下面是遵循DRY原则、高效批量请求且避免重复输出的代码:
const apiKey = "API KEY WITHHELD"; // 复用请求头,避免重复编写 const requestHeaders = new Headers({ "Authorization": apiKey, "Content-Type": "application/json", "Accept": "application/json", "X-Requested-With": "XMLHttpRequest", }); async function fetchPathfinderData() { try { // 1. 获取主endpoint返回的子endpoint列表 const mainResponse = await fetch("https://api.pathfinder2.fr/v1/pf2", { method: 'GET', headers: requestHeaders }); const subEndpoints = await mainResponse.json(); // 2. 并行请求所有子endpoint,避免串行等待浪费时间 const dataPromises = subEndpoints.map(endpoint => fetch(endpoint, { method: 'GET', headers: requestHeaders }).then(res => res.json()) ); // 3. 等待所有请求完成,获取所有数据 const allData = await Promise.all(dataPromises); // 4. 关联endpoint和对应数据,方便后续处理,且只输出一次 subEndpoints.forEach((endpoint, index) => { console.log(`=== ${endpoint.split('/').pop()} 数据 ===`); console.log(allData[index]); }); // 这里可以把allData用于你的搜索页面逻辑 return allData; } catch (error) { console.error("请求出错:", error); } } // 确保函数只执行一次,比如放在页面加载完成后 document.addEventListener('DOMContentLoaded', () => { fetchPathfinderData(); });
手动请求代码的优化建议
如果你暂时不想用批量循环,也可以优化手动请求的代码,同时避免重复执行:
const apiKey = "API KEY WITHHELD"; const requestHeaders = new Headers({ "Authorization": apiKey, "Content-Type": "application/json", "Accept": "application/json", "X-Requested-With": "XMLHttpRequest", }); // 封装通用请求函数,减少重复代码 async function fetchEndpoint(url) { const response = await fetch(url, { method: 'GET', headers: requestHeaders }); return response.json(); } async function getData() { const endpoints = [ "https://api.pathfinder2.fr/v1/pf2/action", "https://api.pathfinder2.fr/v1/pf2/ancestry", "https://api.pathfinder2.fr/v1/pf2/ancestryFeature", "https://api.pathfinder2.fr/v1/pf2/archetype", "https://api.pathfinder2.fr/v1/pf2/background", "https://api.pathfinder2.fr/v1/pf2/class", "https://api.pathfinder2.fr/v1/pf2/classFeature", "https://api.pathfinder2.fr/v1/pf2/deity", "https://api.pathfinder2.fr/v1/pf2/equipment", "https://api.pathfinder2.fr/v1/pf2/feat", "https://api.pathfinder2.fr/v1/pf2/spell" ]; const allData = await Promise.all(endpoints.map(url => fetchEndpoint(url))); // 按顺序输出每个接口的数据,只输出一次 endpoints.forEach((url, index) => { console.log(`=== ${url.split('/').pop()} 数据 ===`); console.log(allData[index]); }); return allData; } // 确保只执行一次 if (!window.pathfinderDataFetched) { getData(); window.pathfinderDataFetched = true; }
关键优化点
- 抽离复用
requestHeaders,彻底遵循DRY原则 - 使用
Promise.all并行发起请求,比串行请求效率高很多 - 避免嵌套循环导致的重复请求,每个子endpoint只请求一次
- 给输出添加标识,方便区分不同接口的数据
- 确保请求函数只执行一次,解决手动请求时的残留重复问题
内容的提问来源于stack exchange,提问作者Sam
相关产品推荐
相关产品推荐

