如何用JavaScript实现请求队列,避免高频API调用被限流?

Zz新利 阅读 73

我在做一个实时搜索功能,输入框每输入一个字符就触发API请求,但发现输入太快会被后端限流。之前用防抖处理过,但用户希望稍微停顿就能立即搜索,所以改成节流,但发现如果用户连续快速输入三次,还是会发三个请求。

我尝试用队列管理请求,写了个简单队列:


let queue = [];
function enqueueRequest(query) {
  queue.push(query);
  if (!timeout) {
    timeout = setTimeout(() => {
      const next = queue.shift();
      sendRequest(next);
      timeout = null;
    }, 0);
  }
}

但发现当快速输入时,队列里的请求还是同时发出去了,后端返回了429错误。是不是队列没有控制并发?或者我的setTimeout用法有问题?有没有更好的实现方式能保证每次只发一个请求,后面自动排队?

我来解答 赞 9 收藏
二维码
手机扫码查看
2 条解答
福萍🍀
你这队列没控制并发,而且setTimeout时间太短压根没用。我一般直接用promise链实现队列:

let queue = Promise.resolve();

function enqueueRequest(query) {
queue = queue.then(() => sendRequest(query));
}
点赞 12
2026-02-04 10:04
开发者雨婷
你这个队列的思路是对的,但问题出在并发控制上。快速输入时,虽然你在用 setTimeout,但如果前面的请求还没返回,后面的又会接着发,这就导致后端看到多个请求同时到达。

我之前也碰到过类似问题,后来改成了这样:每次只发送队列里的第一个请求,等这个请求完成后再处理下一个。可以用 Promise 来监听请求的状态,确保是串行执行。

下面是改进后的代码:

let queue = [];
let processing = false;

function enqueueRequest(query) {
queue.push(query);
processQueue();
}

function processQueue() {
if (processing || queue.length === 0) return;
processing = true;

const next = queue.shift();
sendRequest(next).then(() => {
processing = false;
processQueue(); // 处理完一个后继续处理下一个
}).catch((err) => {
console.error('请求失败:', err);
processing = false;
processQueue(); // 即使失败也继续处理队列
});
}

function sendRequest(query) {
return new Promise((resolve, reject) => {
// 模拟API请求
setTimeout(() => {
console.log('发送请求:', query);
resolve(query); // 成功
// 如果想模拟失败,可以使用 reject(new Error('失败'));
}, 1000); // 假设每次请求耗时1秒
});
}


这样写后,无论用户输入多快,都只会保证一个请求完成后再发下一个。你可以试试看,应该不会再出现429了。

对了,顺便说一句,这种方式确实能解决限流问题,但用户体验上可能会稍有延迟,毕竟要等前一个请求完成。如果还想优化体验,可以结合防抖或者适当减少队列长度,根据实际情况调整。
点赞 8
2026-01-30 20:01