如何实现带可变间隔的递归setTimeout资源批量请求?
实现按间隔批量请求资源的递归setTimeout方案
给定配置
let config = { "requests": [ { "resource": "foo", "interval": 1000 }, { "resource": "bar", "interval": 500 }, { "resource": "baz", "interval": 3000 }, { "resource": "qux", "interval": 500 }, { "resource": "zot", "interval": 500 }, ], // 其他配置... }
需求说明
需要实现递归的setTimeout调用,按以下逻辑批量请求资源:
- 累计500ms时,请求
['bar', 'qux', 'zot']; - 累计1000ms时,请求
['bar', 'qux', 'zot', 'foo']; - 累计1500ms时,再次请求
['bar', 'qux', 'zot']; - 累计3000ms时,请求
['bar', 'qux', 'zot', 'foo', 'baz']; - 以此循环,适配任意未知的间隔配置及资源数量。
初步思路代码
const { requests } = config let intervals = new Set() for (let obj of requests) { intervals.add(obj.interval) } intervals = Array.from(intervals).sort((a, b) => a - b) // [500, 1000, 3000] let currentRequest const makeRequest = resources => { // 携带resources数组向服务器发送请求 // 再次调用initRequest初始化下一次请求 } const initRequest = () => { const interval = 500 // 仅示例,实际间隔需动态计算 const resources = [] // 需在此确定本次请求的资源列表 setTimeout(() => { makeRequest(resources) }, interval) } initRequest()
可行实现方案
核心逻辑是动态计算下一个触发时间点,并筛选出该时间点需要请求的资源,然后递归调度下一次请求:
const { requests } = config; // 记录累计运行时间,初始为0 let totalTime = 0; // 模拟发送请求的函数,可替换为实际请求逻辑 const makeRequest = (resources, triggerTime) => { console.log(`累计${triggerTime}ms,请求资源:`, resources); // 实际场景中这里写axios/fetch等请求代码 }; // 计算下一个触发时间点 const getNextTriggerTime = () => { let nextTime = Infinity; // 遍历所有不同的间隔值,找到大于当前totalTime的最小倍数 const uniqueIntervals = [...new Set(requests.map(item => item.interval))]; for (const interval of uniqueIntervals) { // 计算当前间隔的下一个倍数 const nextMultiple = Math.ceil(totalTime / interval) * interval; if (nextMultiple < nextTime) { nextTime = nextMultiple; } } return nextTime; }; // 筛选当前触发时间点需要请求的资源 const getResourcesToRequest = (triggerTime) => { return requests .filter(item => triggerTime % item.interval === 0) .map(item => item.resource); }; // 递归调度请求的核心函数 const scheduleNextRequest = () => { const nextTriggerTime = getNextTriggerTime(); const delay = nextTriggerTime - totalTime; setTimeout(() => { // 更新累计时间 totalTime = nextTriggerTime; // 获取本次需要请求的资源 const resources = getResourcesToRequest(totalTime); // 发送请求 makeRequest(resources, totalTime); // 递归调度下一次请求 scheduleNextRequest(); }, delay); }; // 启动调度 scheduleNextRequest();
逻辑说明
- 累计时间跟踪:用
totalTime变量记录从启动到当前的累计毫秒数,每次触发请求后更新为当前触发时间点。 - 下一个触发时间计算:遍历所有唯一的间隔值,计算每个间隔的下一个大于当前
totalTime的倍数,取其中最小的那个作为下一次触发时间。 - 资源筛选:在触发时间点,筛选出所有间隔能整除该时间点的资源(即该时间点是资源间隔的整数倍),组成请求列表。
- 递归调度:每次请求发送完成后,立即递归调用调度函数,确保循环执行。
这个方案完全适配未知的间隔配置,不管有多少种间隔值,都能自动计算正确的触发时间和请求资源列表。
内容的提问来源于stack exchange,提问作者Igal
相关产品推荐
相关产品推荐

