JS场景-----页面请求接口大规模并发问题

192 阅读2分钟

解决策略:

  • 队列: 创建一个请求队列,并且同时只处理一定数量的请求。一旦当前处理的请求完成,就从队列中取出下一个请求进行处理。

  • 批处理: 将多个请求合并成一个批量请求,如果 API 支持的话。这减少了请求数量,但可能需要服务器端的支持。

  • 节流: 在特定时间内限制请求的数量。例如,每秒只允许发出一个请求。

  • 防抖: 如果有大量连续的请求,在一定的延迟后只执行最后一次请求,这通常用于搜索框等场景。

  • Promise 控制: 使用 Promise.all 来管理多个请求,或者使用 Promise.race 来处理多个请求中最快返回的结果。

请求队列


class RequestQueue {
  constructor(maxConcurrent) {
    this.maxConcurrent = maxConcurrent; // 设置最大并发数
    this.currentRunning = 0; // 当前正在运行的请求数
    this.queue = []; // 等待执行的请求队列
  }

  // 将请求封装成一个函数,推入队列,并尝试执行
  enqueue(url) {
    return new Promise((resolve, reject) => {
      const task = () => {
        // 当请求开始时,currentRunning 加 1
        this.currentRunning++;
        sendRequest(url).then(resolve).catch(reject).finally(() => {
          // 请求结束后,currentRunning 减 1,并尝试执行下一个请求
          this.currentRunning--;
          this.dequeue();
        });
      };
      this.queue.push(task);
      this.dequeue(); // 每次添加请求后尝试执行请求
    });
  }

  dequeue() {
    // 如果当前运行的请求小于最大并发数,并且队列中有待执行的请求
    if (this.currentRunning < this.maxConcurrent && this.queue.length) {
      // 从队列中取出一个请求并执行
      const task = this.queue.shift();
      task();
    }
  }
}

// 这个函数是模拟发送请求的,实际中你可能需要替换成真实的请求操作
function sendRequest(url) {
  console.log(`Sending request to ${url}`);
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log(`Response received from ${url}`);
      resolve(`Result from ${url}`);
    }, Math.random() * 2000); // 随机延时以模拟请求处理时间
  });
}

// 使用 RequestQueue
const requestQueue = new RequestQueue(3); // 假设我们限制最大并发数为3

// 模拟批量请求
const urls = ['url1', 'url2', 'url3', 'url4', 'url5', 'url6'];
urls.forEach(url => {
  requestQueue.enqueue(url).then(result => {
    console.log(result);
  });
});

总结:

  • enqueue方法:添加请求到队列中,并尝试调用dequeue来执行请求
  • dequeue方法:检查当前执行的请求数量是否小于最大并发数,如果是,从队列中取出请求并执行
  • sendRequest函数:模拟请求的函数,实际使用时需要替换为真实的HTTP请求操作。