前端API请求

286 阅读1分钟

前端API请求

# 前言

今天看了一篇的文章<前端API请求的各种骚操作>, 记录下。

并发控制

需求分析:

  1. 要发起10个请求才能获取全量数据
  2. 控制最多5个并发请求

文中主要使用Promise.all完成需求1,当请求数量达到限制时,使用 await Promise.race 来阻塞循环。

async function requestControl(taskLimit = 2, taskArray = []) {
  const resultTaskArray = [];
  const executingTaskArray = [];
  while(taskArray.length) {
    const taskPromise = taskArray.shift();
    const resultPromise = taskPromise();

    executingTaskArray.push(resultPromise);
    resultTaskArray.push(resultPromise);

    resultPromise.then(() => {
      // 关键点,删除完成的请求
      executingTaskArray.splice(executingTaskArray.indexOf(executingTaskArray), 1);
    })

    // 关键点,限制判断使用await 阻塞循环 发起新的请求
    if (executingTaskArray.length >= taskLimit) {
      await Promise.race(executingTaskArray)
    }
  }
  // 最后返回全部结果
  return Promise.all(resultTaskArray);
}
let i = 0;
function generateRequest() {
  const j = ++i;
  return function request() {
    return new Promise(resolve => {
      console.log(`r${j}...`);
      setTimeout(() => {
        resolve(`r${j}`);
      }, 1000 * j * Math.random());
    })
  }
}
const requestPool = [generateRequest(), generateRequest(), generateRequest(), generateRequest()];

async function main() {
  const results = await requestControl(3, requestPool);
  console.log(results);
}
main();

不使用async await 版本

function requestControl(taskLimit = 2, taskArray = []) {
  const resultTaskArray = [];
  const executingTaskArray = [];

  function dequeue() {
    const taskPromise = taskArray.shift();
    let _promise = Promise.resolve()
    // 递归出口
    if (!taskPromise) {
      return _promise;
    }
    const resultPromise = taskPromise();

    executingTaskArray.push(resultPromise);
    resultTaskArray.push(resultPromise);

    resultPromise.then(() => {
      // 关键点,删除完成的请求
      executingTaskArray.splice(executingTaskArray.indexOf(executingTaskArray), 1);
    })

    // 关键点,通过返回不同的promise 决定是否继续循环
    if (executingTaskArray.length >= taskLimit) {
       _promise = Promise.race(executingTaskArray)
    }
    // 递归
    return _promise.then(dequeue);
  }
  // 最后返回全部结果
  return dequeue().then(() => Promise.all(resultTaskArray))
}

总结

  1. 使用 await Promise.race 来阻塞循环;
  2. 函数里使用promise 进行递归循环;