【发布时间】:2020-07-28 10:16:10
【问题描述】:
我正在围绕 Eve Online 的 ESI api 构建一个站点。我正在使用 NodeJS 使用 axios 进行异步获取调用。我正在尝试使用他们的 api 获取各种游戏区域的市场数据。我已经成功地获取数据并将其添加到我的数据库中,但我觉得我可以以更好更快的方式进行这些调用。他们的 api 在页面中返回结果,每页有 1000 个结果。对于某些地区,我必须请求多达 300 多页,但通常是 100 页。我一直在使用 for 循环执行此操作,然后只检查结果数组是否有数据,如果没有,我会中断 for 循环。对于某些地区,这仅需要几秒钟 10-20 页,而对于其他地区则需要几分钟 50 多页。我正在努力加快速度。现在下载所有内容并上传到我的数据库大约需要 60 分钟,而下载需要花费大量时间。
这是我当前获取数据的代码。我首先得到一个包含所有游戏区域 ID 的列表,然后使用 for 循环遍历每个区域。使用当前区域 ID,我使用它来获取该区域中所有类型的项目 ID。这是我的第一页问题出现的地方。每个区域可以有 1 件商品或 15000 件商品。所以我选择 50 作为任意数字循环直到,检查每个调用是否返回数据。然后我使用相同的区域 ID 执行相同的操作来获取所有订单。这是我的下载时间受到影响的地方。一些地区的订单很少或更多,其中一个地区有 300 多页,在我的笔记本电脑上需要 12 分钟,而在 AWS 设置上需要 4-5 分钟。
const regionData = await axios.get(
"https://esi.evetech.net/latest/universe/regions/?datasource=tranquility"
);
//Eg region 10000042
const region = regionData.data;
console.log(region);
for (let r = 0; r < region.length; r++) {
let typeID = [];
let orders = [];
for (let i = 1; i < 50; i++) {
const types = await axios.get(
`https://esi.evetech.net/latest/markets/${region[r]}/types/?datasource=tranquility&page=${i}`
);
if (types.data.length) {
for (let x = 0; x < types.data.length; x++) {
typeID.push(types.data[x]);
}
} else {
break;
}
}
for (let i = 1; i < 500; i++) {
const results = await axios.get(
`https://esi.evetech.net/latest/markets/${region[r]}/orders/?datasource=tranquility&order_type=all&page=${i}`
);
if (results.data.length) {
for (let x = 0; x < results.data.length; x++) {
orders.push(results.data[x]);
}
} else {
break;
}
}
... code to sort through data and upload to database
}
我想加快这个下载过程,这样我就不必等待每个页面一次下载一个。
我正在尝试使用异步承诺一次下载多个页面,但由于每个区域的页面数量不同,我刚刚选择了一个适合所有人的最大数量,这导致承诺一次进行 300 多个调用,这只是中断并导致 500 错误。当我将页数限制为小于 100 时,它的效果非常好,并且可以在我的 for 循环所用时间的一小部分内获取该数据。我只是不知道如何实现一种方法来循环并获取所有数据,而无需尝试一次请求 300 个页面。
这是我正在测试的当前代码,它使用为类型和订单映射一组 api 链接的 Promise。当它少于 100 页时效果很好,但我开始收到 500 个服务器错误。
let urlsR = [];
let urlsT = [];
const getAllData = async (URLs) => {
return Promise.all(URLs.map(fetchData));
};
function fetchData(URL) {
return axios
.get(URL)
.then(function (response) {
return response.data;
})
.catch(function (error) {
console.log(error)
//return { success: false };
});
}
const regionData = await axios.get(
"https://esi.evetech.net/latest/universe/regions/?datasource=tranquility"
);
const region = regionData.data;
for (let r = 0; r < region.length; r++) {
console.log("Starting API fetch for " + region[r]);
urlsR = [];
urlsT = [];
for (let i = 1; i < 17; i++) {
urlsT.push(
`https://esi.evetech.net/latest/markets/${region[r]}/types/?datasource=tranquility&page=${i}`
);
}
for (let i = 1; i < 316; i++) {
urlsR.push(
`https://esi.evetech.net/latest/markets/${region[r]}/orders/?datasource=tranquility&order_type=all&page=${i}`
);
}
let getTypes = await getAllData(urlsT);
let getMarket = await getAllData(urlsR);
let orders = [];
... Code that sorts through data and uploads to DB
}
我的问题是无法检查每个区域需要请求多少页面,因此我再次选择了一个上限,并且每个区域都针对 api 请求那么多页面。如果没有找到结果,api 只会返回一个空数组,这样可以避免因错误而破坏代码。我只是不想进行 100 次 api 调用,只获得 15 个页面和 85 个空数组,或者尝试一次执行 300 个并不断出错。
抱歉漫无边际,但任何想法或方向都是有帮助的。
【问题讨论】:
-
有什么方法可以确定您可以从
getMarket变量中接收到多少页?它是否为每个页面请求存储一个数组? -
它会为我要求的每个页面获得一个结果,即使没有数据它只是返回一个空数组,因此它将一个空数组推送到变量。所以
getMarket无论如何都会获得 315 页。
标签: javascript node.js api es6-promise