
本文详细介绍了如何通过异步循环机制,从支持分页的api中高效、完整地获取所有数据。针对api每次请求返回结果数量受限的场景,教程演示了如何利用javascript的`async/await`和`fetch`,通过动态调整请求参数(如`start`或`page`),并结合api响应中的总数信息,迭代地请求并累积数据,直至所有可用结果被成功检索。
在与许多Web API交互时,一个常见的情况是API为了优化性能和管理资源,会限制单次请求返回的数据量。例如,一个搜索API可能每次只返回50条结果,即使总共有数百甚至数千条结果可用。为了获取所有数据,开发者需要执行一系列连续的请求,每次请求获取下一批结果,这个过程被称为“分页”。
挑战在于如何有效地管理这些连续请求:
解决上述挑战的关键在于使用一个异步循环结构,它能够:
以下是一个使用JavaScript实现通用API分页数据获取的示例,它模拟了从一个分页API(如Indeed搜索API)获取所有结果的过程。
/**
* 异步函数,用于从支持分页的API获取所有数据。
* 假设API的响应结构包含一个指示总结果数的字段(如 'totalResults')
* 并且支持通过 'start' 和 'limit' 参数进行分页。
*
* @param {string} baseUrl API的基础URL,不包含分页参数。
* @param {object} initialQueryParams 初始查询参数,不包含分页参数。
* @param {number} limitPerPage 每次请求获取的最大结果数。
* @param {string} totalResultsKey API响应中表示总结果数的键名。
* @returns {Promise<Array>} 包含所有从API获取的数据的Promise。
*/
async function fetchAllPaginatedData(baseUrl, initialQueryParams, limitPerPage, totalResultsKey) {
let allResults = []; // 用于累积所有结果的数组
let currentOffset = 0; // 当前请求的起始偏移量
let totalAvailable = Infinity; // 初始设定为无限大,等待API响应提供真实值
// 转换为URLSearchParams对象,便于管理查询参数
const params = new URLSearchParams(initialQueryParams);
// 循环直到所有数据都被获取
while (allResults.length < totalAvailable) {
// 设置当前请求的分页参数
params.set('start', currentOffset.toString());
params.set('limit', limitPerPage.toString());
const url = `${baseUrl}?${params.toString()}`;
try {
console.log(`Fetching data from: ${url}`);
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const responseJson = await response.json();
// 假设API响应的数据字段是 'data',并且总数字段是动态传入的 'totalResultsKey'
const currentBatch = responseJson.data || [];
totalAvailable = responseJson[totalResultsKey] || 0; // 更新总可用结果数
allResults = allResults.concat(currentBatch); // 累积当前批次的数据
// 更新下一个请求的偏移量
currentOffset += currentBatch.length;
// 如果当前批次为空,且allResults.length < totalAvailable,
// 说明可能API已无更多数据,或者API返回的总数不准确,应终止循环
if (currentBatch.length === 0 && allResults.length < totalAvailable) {
console.warn("API returned empty batch but total results suggest more data. Terminating loop to prevent infinite requests.");
break;
}
} catch (error) {
console.error(`Error fetching data: ${error.message}`);
// 在实际应用中,这里可能需要更复杂的错误处理,如重试机制
break; // 遇到错误时终止循环
}
}
console.log(`Finished fetching. Total items collected: ${allResults.length}`);
return allResults;
}
// 模拟Indeed API的调用
// 注意:以下URL和totalResultsKey是示例,实际Indeed API可能需要认证或其他特定参数
const indeedApiBaseUrl = "https://resumes.indeed.com/rpc/search";
const indeedInitialParams = {
q: "sales",
l: "Orlando,FL",
lmd: "3day",
radius: "25",
indeedcsrftoken: "test_tokent" // 示例token
};
const indeedLimit = 50; // Indeed API每次请求的限制
const indeedTotalKey = "totalAvailableResults"; // 假设Indeed API返回的总数键名
// 调用函数并处理结果
(async () => {
try {
const allIndeedResults = await fetchAllPaginatedData(
indeedApiBaseUrl,
indeedInitialParams,
indeedLimit,
indeedTotalKey
);
console.log("All Indeed search results:", allIndeedResults);
// 在这里可以进一步处理所有获取到的数据
} catch (error) {
console.error("Failed to fetch all Indeed results:", error);
}
})();
// 另一个通用API的示例(如问题答案中使用的passenger API)
// 假设该API使用 'page' 和 'size',且总数键名为 'totalPassengers'
const passengerApiBaseUrl = "https://api.instantwebtools.net/v1/passenger";
const passengerInitialParams = {}; // 该API可能不需要初始查询参数
const passengerLimit = 100; // 每次请求的限制
const passengerTotalKey = "totalPassengers"; // API响应中总乘客数的键名
async function fetchAllPaginatedDataByPage(baseUrl, initialQueryParams, limitPerPage, totalResultsKey) {
let allResults = [];
let currentPage = 0; // 从第0页开始
let totalAvailable = Infinity;
const params = new URLSearchParams(initialQueryParams);
while (allResults.length < totalAvailable) {
params.set('page', currentPage.toString());
params.set('size', limitPerPage.toString());
const url = `${baseUrl}?${params.toString()}`;
try {
console.log(`Fetching data from: ${url}`);
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const responseJson = await response.json();
const currentBatch = responseJson.data || [];
totalAvailable = responseJson[totalResultsKey] || 0;
allResults = allResults.concat(currentBatch);
currentPage++; // 切换到下一页
if (currentBatch.length === 0 && allResults.length < totalAvailable) {
console.warn("API returned empty batch but total results suggest more data. Terminating loop.");
break;
}
} catch (error) {
console.error(`Error fetching data: ${error.message}`);
break;
}
}
console.log(`Finished fetching. Total items collected: ${allResults.length}`);
return allResults;
}
(async () => {
try {
const allPassengers = await fetchAllPaginatedDataByPage(
passengerApiBaseUrl,
passengerInitialParams,
passengerLimit,
passengerTotalKey
);
console.log("All passengers:", allPassengers);
} catch (error) {
console.error("Failed to fetch all passengers:", error);
}
})();fetchAllPaginatedData 函数:
循环条件 while (allResults.length < totalAvailable):
请求参数设置:
fetch 和 async/await:
数据累积与偏移量更新:
终止条件细化:
错误处理:
API特定性:
通过异步循环结合动态参数调整和API响应中的总数信息,我们可以构建出健壮且高效的JavaScript代码来获取支持分页的API的所有数据。理解async/await、fetch以及如何根据API文档调整分页逻辑是实现这一功能的关键。务必考虑错误处理、API速率限制等因素,以确保应用程序的稳定性和可靠性。
以上就是API分页数据循环获取教程的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号