前端ajax请求并发数量控制

246 阅读1分钟

场景:比如前端轮询上传多张图片(几十几百张),控制并发上传数量

1.发送全部请求,即便中间有进入reject的

// 模拟ajax请求
const getRequest = (n) => {

  return new Promise((resolve, reject) => {
    // 请求0-3s返回

    const t = Math.random() * 3 * 1000

    setTimeout(() => {

      console.log(`${n}完成,耗时${t}`);

      resolve([n, t])

    }, t)

  })

}
// 主函数
const limitRequest = async(maxRequstQuantity, allReq, fetchFn) => {

  const result = [];

  const queue = [];

  for (let i = 0; i < allReq; i++) {

    console.log(`${i}发起请求`);

    const promise = fetchFn(i);

    // 执行完从queue中删除自身

    promise.finally(() => {

      const index = queue.indexOf(promise); // queue.indexOf(promise)是可以找到正确位置的

      console.log(`${i}完成,当前所在位置`, index);

      queue.splice(index, 1);

    })

    result.push(promise);

    queue.push(promise);

    // 如果queue中的数量达到maxRequstQuantity,等一个请求完成再进行后面的for循环(这里是关键,阻塞for)

    if (queue.length >= maxRequstQuantity) {

      await Promise.race(queue);

    }

  }

  return Promise.allSettled(result); // Promise.allSettled所有请求执行完,不区分状态是res还是rej([{"status": "fulfilled","value": [0,118]}])

}

2.当有请求失败时,结束后面的请求(场景:前端弹框提示错误)

// 模拟ajax请求,n为4的请求进入reject
const getRequest = (n) => {

  return new Promise((resolve, reject) => {
    // 请求0-3s返回

    const t = Math.random() * 3 * 1000

    setTimeout(() => {

      console.log(`${n}完成,耗时${t}`);

      if (n != 4) {

        resolve([n, t])

      } else {

        reject([n, t])

      }

    }, t)

  })

}
// 主函数
const limitRequest2 = async(maxRequstQuantity, allReq, fetchFn) => {

  const result = [];

  const queue = [];

  try {

    for (let i = 0; i < allReq; i++) {

      console.log(`${i}发起请求`);

      const promise = fetchFn(i);

      // 执行完且成功,从queue中删除自身

      promise.then(() => {

        const index = queue.indexOf(promise); // queue.indexOf(promise)是可以找到正确位置的

        // console.log(`${i}完成,当前所在位置`, index);

        queue.splice(index, 1);

      })

      result.push(promise);

      queue.push(promise);

      // 如果queue中的数量达到maxRequstQuantity,等一个请求完成再进行后面的for循环(这里是关键,阻塞for)

      if (queue.length >= maxRequstQuantity) {

        await Promise.race(queue)

      }

    }

  } catch(err) {
    // 可以拿到错误的请求是哪个
    console.log('err', err)

  }

  return Promise.allSettled(result) // Promise.allSettled所有请求执行完,不区分状态是res还是rej([{"status": "fulfilled","value": [0,118]}])

}

测试函数,执行limitRequest为例(发送全部请求)

const test = async() => {

  // results的数据结构是[{"status": "fulfilled","value": [0,118]}],自己判断每个请求的状态

  const results = await limitRequest(3, 8, getRequest);

  console.log(results)
  
  const results2 = await limitRequest(3, 10, getRequest);

  console.log(results2);

}

test()执行输出

(1)await limitRequest(3, 8, getRequest);

图片.png

(2)await limitRequest(3, 10, getRequest);

图片.png