实现请求的并发控制

278 阅读2分钟

前言

对于请求的并发控制也是前端优化的一个重要环节,大量的请求会给后台服务器很大的压力,也会给网络带来压力,页面会出现卡顿。上代码

使用Promise.race和async await特性实现

在以上代码中,充分利用了 Promise.all 和 Promise.race 函数特点,再结合 ES7 中提供的 async await 特性,最终实现了并发控制的功能。

利用 await Promise.race(executing); 这行语句,我们会等待 正在执行任务列表 中较快的任务执行完成之后,才会继续执行下一次循环。

//请求
let a = () => {
  return new Promise((res, rej) => {
    axios({
      method: "get",
      url: "/request"
    }).then((response) => {
      res(response.data)
    }).catch((err) => {
      rej(err)
    })
  })
}
//请求的并发控制
async function asyncPool(poolLimit, requestList, iteratorFn) {
  const ret = []; // 存储所有的异步任务
  const executing = []; // 存储正在执行的异步任务
  for (const item of requestList) {
    // 调用iteratorFn函数创建异步任务,请求也是在时候发出
    const p = Promise.resolve().then(() => iteratorFn(item, requestList));
    ret.push(p); // 保存新的异步任务
    // 当poolLimit值小于或等于总任务个数时,进行并发控制
    if (poolLimit <= requestList.length) {
      // 当任务完成后,从正在执行的任务数组中移除已完成的任务
      const e = p.then(() => executing.splice(executing.indexOf(e), 1)).catch(() => { executing.splice(executing.indexOf(e), 1) });
      // 保存正在执行的异步任务
      executing.push(e);
      // 当任务到达设定长度时,使用await和
      if (executing.length >= poolLimit) {
        // 等待较快的任务执行完成
        await Promise.race(executing);
      }
    }
  }
  return Promise.all(ret);
}
// 对每一个请求进行处理
function processing(everyRequest, requestList) {
  return new Promise((res, rej) => {
    everyRequest().then((val) => {
      console.log(val);
      res(val)
    }).catch((err) => {
      console.log(err);
      rej(err)
    })
  })
}
asyncPool(2, [a, a, a], processing).then((val) => {
  console.log(val);
}).catch((err) => {
  console.log('有失败请求', err);
})

使用Promise.race

通过内部封装的 enqueue 函数来实现核心的控制逻辑。

当 Promise.race(executing) 返回的 Promise 对象变成已完成状态时,才会调用 enqueue 函数,从 requestList 数组中获取新的待办任务。

let a = () => {
  return new Promise((res, rej) => {
    axios({
      method: "get",
      url: "/request"
    }).then((response) => {
      res(response.data)
    }).catch((err) => {
      rej(err)
    })
  })
}

function asyncPool(poolLimit, requestList, iteratorFn) {
  let i = 0;
  const ret = []; // 存储所有的异步任务
  const executing = []; // 存储正在执行的异步任务
  const enqueue = function () {
    if (i === requestList.length) {
      return Promise.resolve();
    }
    // 获取新的任务项
    const item = requestList[i++];
    // 调用iteratorFn函数创建异步任务,请求也是在时候发出
    const p = Promise.resolve().then(() => iteratorFn(item, requestList));
    ret.push(p);
    let r = Promise.resolve();
    // 当poolLimit值小于或等于总任务个数时,进行并发控制
    if (poolLimit <= requestList.length) {
      // 当任务完成后,从正在执行的任务数组中移除已完成的任务
      const e = p.then(() => executing.splice(executing.indexOf(e), 1)).catch(() => { executing.splice(executing.indexOf(e), 1) });
      // 保存正在执行的异步任务;
      executing.push(e);
      if (executing.length >= poolLimit) {
        r = Promise.race(executing);
      }
    }
    // 正在执行任务列表 中较快的任务执行完成之后,才会调用enqueue函数requestList数组中获取新的待办任务
    return r.then(() => enqueue());
  };
  return enqueue().then(() => Promise.all(ret));
}
// 对每一个请求进行处理
function processing(everyRequest, requestList) {
  return new Promise((res, rej) => {
    everyRequest().then((val) => {
      console.log(val);
      res(val)
    }).catch((err) => {
      console.log(err);
      rej(err)
    })
  })
}
asyncPool(2, [a, a, a], processing).then((val) => {
  console.log(val);
}).catch((err) => {
  console.log('有失败请求', err);
})

结语

不懂的可以去试试