Deno 1.44.4中基于setTimeout的限流器请求排队问题求助
问题根源
你的限流器逻辑是批量清空所有等待请求,然后等待5秒再进入下一轮,而非你预期的「请求间添加延迟」:
- 当第一个请求进来,
callLimiter启动limiter,limiter会一次性处理队列里的所有请求,然后设置5秒定时器 - 在这5秒等待期间,新进来的请求只会被加入
requests队列,但因为timerInstance不为0,callLimiter不会触发新的limiter执行 - 只有等5秒定时器结束,
limiter才会再次运行,批量处理这段时间积累的所有请求,导致超过2个请求时,后续请求必须等待定时器完成才能响应
修复代码
改成逐个处理队列请求,每个请求之间间隔5秒的逻辑,修改后的完整代码如下:
const headers = { "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Methods": "*", "Access-Control-Allow-Headers": "*" } const REQUEST_LIMITER = { timerInstance: null, requests: new Map() }; Deno.serve({ port: 9000 }, requestHandler); async function requestHandler(req: Request) { console.log("----- New Request recieved -----"); if (req.url.endsWith("test")) return await testController(); return Response.json({ status: "error", message: "Invalid API endpoint" }, { status: 404, headers }); } async function testController() { return new Promise((resolve) => { const requestId = crypto.randomUUID(); REQUEST_LIMITER.requests.set(requestId, { resolve }); callLimiter(); }).then(data => { return Response.json({ status: "success", data }, { status: 200, headers }); }); } function callLimiter() { // 如果没有正在运行的定时器,且队列有请求,启动处理流程 if (!REQUEST_LIMITER.timerInstance && REQUEST_LIMITER.requests.size > 0) { processNextRequest(); } } function processNextRequest() { // 取出队列中的第一个请求 const [requestId, { resolve }] = REQUEST_LIMITER.requests.entries().next().value; REQUEST_LIMITER.requests.delete(requestId); // 响应当前请求 resolve("Resolved"); // 如果队列还有请求,设置5秒延迟后处理下一个 if (REQUEST_LIMITER.requests.size > 0) { REQUEST_LIMITER.timerInstance = setTimeout(() => { REQUEST_LIMITER.timerInstance = null; processNextRequest(); }, 5000); } else { // 队列为空,清空定时器标记 REQUEST_LIMITER.timerInstance = null; } }
测试页面修复
你的测试代码里fetch未加await,会导致读取response.status时出错,修改后的测试页面代码:
<!DOCTYPE html> <html lang="en"> <head></head> <body> <button onclick="makeAPICall()">Make Request</button> <p id="result"></p> <script> async function makeAPICall() { try { const response = await fetch("http://localhost:9000/test"); if (response.status === 200) { const responseData = await response.json(); // 追加结果,方便查看多个请求的响应顺序 document.getElementById("result").innerHTML += `<br>${responseData.data}`; } } catch (err) { console.error(err); } } </script> </body> </html>
效果验证
- 连续点击按钮发送多个请求,第一个请求会立即响应
- 后续每个请求会在前一个请求响应后等待5秒再响应,完全符合「请求间添加延迟」的需求
内容的提问来源于stack exchange,提问作者supxd
相关产品推荐
相关产品推荐

