Skip to content

前端并发请求的逻辑

指定一个url的数组,和一个最大的并发数,假定最大数是3,那么同时可发出的请求就是 3 个,当这个 3 个之中有一个完成了,就立刻取数组中的下一个url进行请求。

并且最后的返回结果的顺序,也要和url数组的顺序保持一致。

request01

实现

根据要求,我们要封装的函数肯定是一个异步函数,返回的结果是一个Promise,而这个Promise,一定也要是完成状态的,也就是只调用resolve函数。也就是说,当A接口请求成功后,我们把成功的结果放到返回数组对应位置,如果失败了,也要把失败的信息放到返回数组的对应位置。

js
function concurRequest(urls, maxNum = 5) {
  return new Promise((resolve) => {
    if (urls.length === 0) {
      resolve([]);
      return;
    }

    const results = [];
    let index = 0; // 下一个请求的下标
    let count = 0; // 当前请求完成的数量

    // 执行请求
    async function request() {
      if (index >= urls.length) return;

      const i = index; // 保存当前下标,请求完成时把结果放到对应的位置
      const url = urls[index++];

      try {
        const resp = await fetch(url);
        // resp 加入到 results
        results[i] = resp;
      } catch (err) {
        // err 加入到 results
        results[i] = err;
      } finally {
        // 判断是否所有的请求都已完成
        if (++count >= urls.length) {
          resolve(results);
        }

        // 当前请求完成后,继续取下一个 url 执行请求
        request();
      }
    }

    // 防止最大请求数超出了实际的 url 个数
    const times = Math.min(maxNum, urls.length);

    // 发出并发请求
    for (let i = 0; i < times; i++) {
      request();
    }
  });
}

使用

js
const urls = [];
for (let i = 1; i <= 10; i++) {
  urls.push(`https://jsonplaceholder.typicode.com/todos/${i}`);
}

// 最大并发数 3
concurRequest(urls, 3).then((resps) => {
  console.log(resps);
});

结果