利用promise在js中实现请求的并发控制

前言

发送请求对于前端来说是很正常的工作,一般情况,当我们进入页面时,常常直接将请求全部发送出去,这样会导致一些问题的发生。

  • 性能问题:大量的请求会增加服务器的负载和网络流量,可能导致服务器性能下降,响应时间延长,甚至导致服务器崩溃。

  • 网络拥塞: 大量的请求同时发送可能会导致网络拥塞,尤其是在高流量时段或者网络条件较差的情况下。

  • 服务器端资源耗尽: 如果服务器没有足够的资源来处理所有的请求,例如内存或者处理器资源,那么可能会出现资源耗尽的情况,导致服务器无法正常工作。

  • 用户体验下降: 大量的请求可能会导致页面加载速度变慢,甚至出现页面加载失败或者部分内容加载不全的情况,从而影响用户体验。

  • 安全问题: 大量的请求可能会被视为恶意行为,触发服务器的安全防护机制,导致请求被拦截或者IP被封锁。

所以为了保证系统的稳定性和良好的用户体验,我们需要合理的控制请求的并发数量。

实现请求的发生

现在我们将通过一个按钮的点击,来进入页面时请求的发送。

<button id='btn'>
  点击发送请求
</button>

获取按钮

const btn = document.getElementById('btn');

构造请求,可以通过node简单的启动一个后端

const mookRequest = (id) => {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open('GET', `http://127.0.0.1:9527/${id}`, true);
    xhr.send();
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4) {
        if (xhr.status === 200) {
          resolve(xhr.responseText);
        } else {
          reject(new Error('Request failed with status ' + xhr.status));
        }
      }
    };
  });
};

发送请求

btn.addEventListener('click', () => {
  mookRequest('test1')
  mookRequest('test2')
  mookRequest('test3')
  mookRequest('test4')
  mookRequest('test5')
});

现在我们点击按钮,检查控制台,可以发现已经成功的将五个请求同时发送出去了

如果现在我们将增加如下需求

  • 最多只能存在三个并发的请求
  • 每有一个请求完成,自动发送剩余的请求

接下来,我们将通过promise.race来实现并发

function limitRequest() {
    // 并发池
  const requestList = []
 
  // 最大并发数
  const limit = 3 
 
  // 请求地址
  const urls = ['test1', 'test2', 'test3', 'test4', 'test5']
 
  // 添加请求
  const addrequest = (url) = >{
    const request = mookRequest(url);
    // 往并发池添加任务
    requestList.push(task);
    task.then((res) => {
      // 请求结束后将该任务从并发池中移除
      requestList.splice(pool.indexOf(task), 1);
    });
  }
 
  // 发现有请求完成,就增加任务
  const watchRequest = (race) => {
    race.then(() => {
      let url = urls.shift();
      if (url !== undefined) {
        addTask(url);
        run(Promise.race(pool));
      }
    });
  };
 
  // 初始化并发池
  while (requestList.length < limit) {
    let url = urls.shift();
    if (!url) break;
    addTask(url);
  }
 
  // 通过promise.race获取是否有请求已经完成
  const race = Promise.race(pool);
 
  watchRequest(race);
}
 
 

发送请求

btn.addEventListener('click', () => {
  limitRequest()
});

观察控制台,已经完美的实现了我们的需求。

总结

在这个需求中我们还需要了解promise.race的用法。Promise.race() 方法是 Promise 并发方法之一。当你想要第一个异步任务完成时,但不关心它的最终状态(即它既可以成功也可以失败)时,它就非常有用。

通过本文的介绍,我们了解了在前端开发中如何合理控制请求的并发数量,以解决可能出现的性能问题、网络拥塞、服务器资源耗尽、用户体验下降以及安全问题等一系列挑战。我们通过使用 Promise 和 Promise.race 方法来实现了并发控制的功能,确保最多只存在三个并发的请求,并在一个请求完成后自动发送剩余的请求。这种实现方式不仅提高了系统的稳定性和性能,还能有效改善用户体验。在实际项目中,合理控制请求的并发数量是非常重要的。感谢您的阅读!