调用分页API时axios返回空数组?getIds函数Promise及循环写法问题
问题根本原因
你遇到的外层打印空数组、内层能正常打印数据的现象,本质是Promise resolve的执行时机远早于axios异步请求的回调执行时机,和你怀疑的resolve逻辑位置错误完全吻合。具体的代码执行时序是完全固定的:
- 进入
getIds函数,初始化空的filterdIds数组,构造好axios请求的配置参数 - 进入do循环块,调用
axios(config)发起网络请求——axios请求是异步非阻塞的,调用之后不会等待接口返回结果,直接向下执行同步代码 - 因为你测试用的循环判断条件是
pageNumber != 1,第一次循环走完后直接跳出do-while结构,同步执行resolve(filterdIds)——这个时候filterdIds还是初始的空数组,因为axios的.then回调还在排队等网络请求返回,根本没执行到push数据的步骤 - 等几百毫秒后接口返回结果,事件循环把axios的.then回调推入执行队列,才开始往
filterdIds里push匹配的id,打印出有实际值的数组。但这个时候外层的Promise早就把空数组传递给下游的.then链路了,自然只能拿到空结果。
核心坑点来自JS的事件循环规则:所有同步代码会优先于异步回调(包括Promise的then微任务)执行完毕。只要在同步代码里完成了Promise的resolve操作,后续异步操作对原始变量的修改,都不会影响已经被resolve出去的结果。
修正逻辑的核心要求
- 绝对不能在Promise构造函数的同步执行路径里直接调用resolve,必须等所有分页请求完成、符合条件的id全部收集完毕之后,再调用resolve把最终结果抛出去
- reject逻辑的放置位置没有固定要求,只要在捕获到请求失败、分页逻辑异常中断的时机调用即可,不需要绑定到do-while循环的特定位置
- 原本在axios的.catch里只打印错误的写法必须修改:如果请求失败不调用reject,会导致整个Promise一直处于pending状态,外层链路永远拿不到返回值
适配分页爬取规则的参考实现
分页爬取的逻辑不能靠同步的do-while循环控制——循环本身是同步执行的,根本跟不上异步网络请求的返回节奏,用递归+await串行请求的方式控制翻页逻辑会稳定很多,参考代码如下:
function getIds(jwt) { return new Promise((resolve, reject) => { let pageNumber = 1; const filterdIds = []; // 递归实现单页请求,匹配原有的分页规则 async function fetchCurrentPage() { try { const config = { // 原有接口配置,补充动态的分页参数 params: { page: pageNumber } }; const pageResponse = await axios(config); let needFetchNextPage = true; pageResponse.data.forEach(element => { // 原有业务判断:条件满足时收集id filterdIds.push(element.id); // 原分页判断逻辑:如果记录不是昨日产生的,终止翻页 if (new Date(element.createTime).toDateString() !== new Date(Date.now() - 86400000).toDateString()) { needFetchNextPage = false; } }); // 判断是否需要爬取下一页 if (needFetchNextPage) { pageNumber++; return fetchCurrentPage(); } // 所有页爬取完成,返回收集到的id数组 resolve(filterdIds); } catch (error) { // 任何环节出错直接把错误抛给外层链路 reject(error); } } // 启动第一页的请求 fetchCurrentPage(); }); }
常见踩坑提醒
- 只要Promise内部存在异步操作,就不要在同步路径里调用resolve/reject,这是“外层拿到空值、内层能打印到正确数据”这类问题的最常见诱因
- 不要在do-while循环里直接发起axios请求,循环不会等待每一页请求返回就会直接跑完所有迭代步骤,根本没法根据接口返回结果判断是否要翻页
内容的提问来源于stack exchange,提问作者RemcoE33
相关产品推荐
相关产品推荐

