在JavaScript Promise函数中遍历API多页响应的实现方案
如何递归获取所有分页API数据并一次性返回完整结果?
你的思路是对的,用递归遍历所有分页,但问题出在递归调用时没有等待子请求完成就结束了当前Promise,导致最初的调用无法拿到所有数据。我来帮你修复这个问题,同时提供两种更清晰的实现方式:
方案一:用Async/Await实现(推荐,更易读)
Async/await可以让异步逻辑看起来像同步代码,递归时能直观地等待下一页数据返回再合并:
const getContacts = async (token, startFrom = null) => { let currentUrl = url; if (startFrom) { currentUrl = `${url}?${startFrom}`; } try { // 发起当前页请求 const response = await fetch(currentUrl, { method: 'GET', headers: { 'Content-Type': 'application/json', // 注意:这里要补上token认证头,比如API用Bearer认证的话: // Authorization: `Bearer ${token}` }, }); const data = await response.json(); // 检查是否有下一页 const nextLink = data.links.find(link => link.rel === 'next'); if (nextLink) { // 递归获取下一页数据,等待结果返回 const nextPageData = await getContacts(token, nextLink.uri); // 合并当前页和后续所有页的数据(如果data.data是对象用展开运算符,是数组就用concat) return { data: { ...data.data, ...nextPageData.data } }; } else { // 没有下一页,直接返回当前页数据 return { data: data.data }; } } catch (err) { // 抛出错误让调用方的catch处理 throw err; } };
方案二:修复你原来的Promise链式调用版本
如果你更习惯用传统的Promise写法,核心是要等待递归的Promise完成后再resolve当前Promise,不能直接调用递归就结束:
const getContacts = (token, allData = {}, startFrom = null) => new Promise((resolve, reject) => { let currentUrl = url; if (startFrom) { currentUrl = `${url}?${startFrom}`; } fetch(currentUrl, { method: 'GET', headers: { 'Content-Type': 'application/json', // 同样记得补上token认证头 // Authorization: `Bearer ${token}` }, }) .then(response => response.json()) .then((data) => { // 合并当前页数据到allData Object.assign(allData, data.data); const nextLink = data.links.find(link => link.rel === 'next'); if (nextLink) { // 关键:递归调用后,要在它的then里再resolve当前Promise getContacts(token, allData, nextLink.uri) .then(() => resolve({ data: allData })) .catch(reject); } else { // 没有下一页,直接返回合并后的所有数据 resolve({ data: allData }); } }) .catch(reject); });
调用方式(和原来一致)
不管用哪种方案,调用代码都不用改,现在data.data会包含所有分页的完整数据:
getContacts(token) .then((data) => { const contacts = data.data; console.log(contacts); // 现在是所有页的集合了 }) .catch(err => console.error(err));
几个注意点
- 认证头补充:你原来的代码里fetch没有带token,这大概率会导致API请求失败,记得根据API要求添加认证头(比如Bearer Token)。
- 数据结构适配:如果
data.data是数组而不是对象,合并时要改成allData.push(...data.data),返回时return { data: allData }。 - 递归安全:可以考虑添加递归深度限制,防止API返回无限循环的
next链接导致栈溢出或无限请求。
内容的提问来源于stack exchange,提问作者 rok
相关产品推荐
相关产品推荐

