JavaScript 控制异步接口并发数量的实现方案

作者:木棉时间:2026-10-23 23:50:46浏览:280

本文介绍在 JavaScript 中控制异步接口并发数量的两种实现方式。针对批量 URL 请求,通过 max 参数限制同时发起的请求数,并在所有请求完成后执行回调。文章对比了基于递归队列的简易实现与利用 Promise.all 的优化方案,解析了 Promise 执行特性及阻塞问题,提供完整代码示例供参考。

需求描述与核心逻辑

请实现如下函数,其中发起网络请求可直接使用 fetch 方法。

  1. 支持批量获取数据,所有待请求的 URL 地址通过 urls 参数传入。
  2. 同时,可以通过 max 参数来限制请求的并发数量。
  3. 当所有请求执行完毕后,需要执行 callback 回调函数。

function sendRequest (urls: string[], max: number, callback: () => void) {}

fetch 函数返回的是一个 Promise 对象,而 Promise 在实例化时即开始执行。

简易实现:基于队列的递归控制

简易实现方案


function fetch(url) {
 // 模拟接口请求
 return new Promise(resolve => {
   setTimeout(() => {
     resolve(url)
   }, 10000*Math.random())
 })
}

/**
 * 接口请求最大并发量控制
 * @param { Array } urls 接口请求地址数组集合
 * @param { Number } max 最大并发量
 * @param { Function } callback 回调函数 
 */
function maxRequestLimit(urls, max, callback) {
 // 如果没有传入urls或max则不继续执行
 if (!urls || !max) return

 // 当请求地址数组集合长度为0,则执行回调函数(如果有的话),并结束后续执行
 if(urls.length === 0) {
   if(callback) callback()
   return
 }
 
 // 使用splice方法返回当前要使用的请求集合,同时删除原有的请求集合
 const onceMaxUrlArr = urls.splice(0, max)

 // 进行map转换,将url参数转换为promise
 const onceMaxFetchArr = onceMaxUrlArr.map(url => fetch(url))

 // 使用当前这一队列
 Promise.all(onceMaxFetchArr)
 .then(res => {
  console.log(res)
  // 递归请求
  maxRequestLimit(urls, max, callback)
 })
}

maxRequestLimit(['url1', 'url2', 'url3', 'url4', 'url5', 'url6', 'url7', 'url8'], 3, () => {console.log('fetch end')})

上述简易实现采用队列模式逐个或分批进行请求,实际运行中可能存在一定的阻塞现象。下面通过进一步优化来提升请求效率。

优化实现:结合 Promise.all 提升效率

完善实现方案


function fetch(url) {
 // 模拟接口请求
 return new Promise(resolve => {
  setTimeout(() => {
   resolve(url)
  }, 10000 * Math.random())
 })
}

/**
 * 接口请求最大并发量控制
 * @param { Array } urls 接口请求地址数组集合
 * @param { Number } max 最大并发量
 * @param { Function } callback 回调函数 
 */
function maxRequestLimit(arr, max, callback) {
 // 如果没有传入urls或max则不继续执行
 if (!arr || !max) return

 // 当请求地址数组集合长度为0,则执行回调函数(如果有的话),并结束后续执行
 if(arr.length === 0) {
   if(callback) callback()
   return
 }

 let fetchArr = [], // 存储并发max的promise数组
  i = 0;

 function toFetch() {
  // 所有的请求都受理,则返回一个resolve
  if (i === arr.length) return Promise.resolve()

  // 取出第i个url, 放入fetch里面 , 每取一次i++
  let one = fetch(arr[i++]) 

  //将当前的promise存入并发数组中
  fetchArr.push(one) 

  // 当promise执行完毕后,从数组删除
  one.then(res => { 
   console.log(res)
   fetchArr.splice(fetchArr.indexOf(one), 1) 
  }) 

  let p = Promise.resolve()

  // 当并行数量达到最大后, 用race比较 第一个完成的, 然后再调用一下函数自身。
  if (fetchArr.length >= max) p = Promise.race(fetchArr)

  return p.then(() => toFetch())
 }

 // arr循环完后, 现在fetchArr里面剩下的promise对象, 使用all等待所有的都完成之后执行callback
 toFetch()
 .then(() => Promise.all(fetchArr))
 .then(() => callback())
}


maxRequestLimit(['url1', 'url2', 'url3', 'url4', 'url5', 'url6', 'url7', 'url8'], 3, () => { console.log('fetch end') })

总结

总结

至此,关于 JavaScript 异步接口并发数量控制的文章介绍完毕。如需了解更多相关 JS 异步接口并发控制内容,请搜索本站历史文章或继续浏览下方相关文章。感谢大家的支持!

作者最新文章