JavaScript实现拆分日期区间调用API,获首个有数据段即停止请求
问题分析与修复方案
你的代码主要存在以下几个问题:
- 日期变量逻辑错误:你把
startDate和endDate搞反了,startDate应该是更早的日期,endDate是较晚的日期,否则日期范围计算和API请求都会出错。 - 异步请求未正确处理:
requestToDataNews返回的是Promise,你直接通过newsData.is_success判断是无效的,Promise对象本身没有这个属性,必须用await或.then()等待请求完成后再处理数据。 - 日期区间计算错误:用
subtract('months', 2)不能精确得到90天的区间,应该用subtract(90, 'days');同时每次循环需要将endDate更新为当前区间的startDate,才能正确往前推移90天。 - 未实现"获取到首个有数据的区间就停止"的逻辑:原循环会跑完所有区间,没有在拿到有效数据后终止循环。
- Loading状态管理混乱:每个请求的
finally都会关闭loading,导致循环中后续请求还在进行时loading就被关掉了。
修复后的代码
async function fetchFirstValidNewsData(originalStart, originalEnd) { // 确保日期顺序正确,start是更早的日期 const startDate = moment.min(moment(originalStart), moment(originalEnd)); const endDate = moment.max(moment(originalStart), moment(originalEnd)); const differentDays = endDate.diff(startDate, 'days'); const currentNewsData = []; // 只处理90-365天的范围 if (differentDays <= 90 || differentDays > 365) { // 范围小于等于90天直接请求 const data = await requestToDataNews(startDate.format('YYYY-MM-DD'), endDate.format('YYYY-MM-DD')); if (data.is_success) { currentNewsData.push(...data.data); } return currentNewsData; } commit('loadingBar', true); let currentEnd = endDate.clone(); const maxLoops = Math.ceil(differentDays / 90); try { for (let i = 0; i < maxLoops; i++) { // 计算当前区间的开始日期:当前结束日期往前推90天 const currentStart = currentEnd.clone().subtract(90, 'days'); // 确保不超过原始的开始日期 const actualStart = moment.max(currentStart, startDate); const newsData = await requestToDataNews(actualStart.format('YYYY-MM-DD'), currentEnd.format('YYYY-MM-DD')); if (newsData.is_success && newsData.data.length > 0) { currentNewsData.push(...newsData.data); // 拿到有效数据,终止循环 break; } // 没有数据,将当前结束日期更新为当前区间的开始日期前一天,继续往前找 currentEnd = actualStart.clone().subtract(1, 'days'); // 如果已经到了原始开始日期,停止循环 if (currentEnd.isBefore(startDate)) break; } } catch (error) { console.error('请求新闻数据失败:', error); // 可在此添加错误提示等逻辑 } finally { commit('loadingBar', false); } return currentNewsData; } // 原请求函数修正:移除内部的loading状态变更,统一由外部管理 function requestToDataNews(startDate, endDate) { return new Promise((resolve, reject) => { http.get(`/test=&start_date=${startDate}&end_date=${endDate}`, { timeout: 40000 }) .then((response) => { if (response.data.response_code === 200) { resolve(response.data); } else { reject(response.data); } }) .catch((error) => { reject(error); }); }); } // 调用示例 fetchFirstValidNewsData('2021-12-27', '2022-12-27');
关键改动说明
- 日期顺序校正:用
moment.min和moment.max确保startDate始终早于endDate,避免传入顺序错误导致的问题。 - 异步请求处理:使用
async/await等待请求完成,确保能正确获取到返回的is_success和data字段。 - 正确的区间推移:每次循环将
currentEnd更新为上一个区间的startDate前一天,确保区间不重叠且覆盖整个范围;同时添加判断,避免超过原始的开始日期。 - 终止逻辑实现:在拿到
is_success为true且数据不为空时,立即break终止循环,符合需求。 - Loading状态统一管理:将loading的开启和关闭移到循环外部的
try/finally中,确保所有请求完成后才关闭loading。 - 请求函数优化:移除请求函数内部的
commit('loadingBar', false),避免多次请求时混乱的loading状态。
内容的提问来源于stack exchange,提问作者peanut
相关产品推荐
相关产品推荐

