前端如何控制并发请求数量?

最近领导给了一个需求——大文件上传,由于文件过大(几百MB),故而采取了分片上传机制,将大文件分割成了多个小分片进行上传;此时出现了这样一个问题:

  1. 浏览器支持并发请求,谷歌浏览器貌似是从59版本开始,支持并发请求数为 6
  2. 大文件共分了100片,待请求资源就有100个,依次排队,它们在一定时间内会占用全部的并发请求数,导致其他请求无法下发。

这时,就需要控制分片上传请求的并发数不能占满 6 个,影响其他请求下发;这个问题可以转化成实现一个并发请求函数concurrencyRequest(urls, maxNum),要求如下:

  • 最大并发数 maxNum = 3;
  • 每当有一个请求返回,就留下一个空位,可以增加新的请求;
  • 所有请求完成后,结果按照urls顺序依次打印出来,返回一个results集合;

需要考虑的特殊情况:

  • urls 的长度为 0results 为空数组;
  • maxNum 大于 urls 的长度,应该取的是 urls 的长度;
  • 需要定义一个 count 计数器来判断是否已全部请求完成;
  • 由于没有考虑请求是否请求成功,所以请求成功或报错都应该把结果保存在 results 集合中;
  • results 中的顺序需和 urls 中的保持一致;
// 并发请求函数
const concurrencyRequest = (urls, maxNum) => {
    
    
    return new Promise((resolve) => {
    
    
    	// 特殊情况,urls长度为0
        if (urls.length === 0) {
    
    
            resolve([]);
            return;
        }
        
        const results = []; 
        let index = 0; // 下一个请求的下标
        let count = 0; // 当前请求完成的数量

        // 发送请求,一个请求结束之后才能进行下一个请求
        async function request() {
    
    
            if (index === urls.length) return;
            const i = index; // 保存序号,使results和urls相对应
            const url = urls[index];
            index++;
            console.log(`${
      
      i}个 url`, url);
            try {
    
    
                const resp = await fetch(url);
                // resp 加入到results
                results[i] = resp;
            } catch (err) {
    
    
                // err 加入到results
                results[i] = err;
            } finally {
    
    
                count++;
                // 判断是否所有的请求都已完成
                if (count === urls.length) {
    
    
                    console.log('完成了所有的请求');
                    resolve(results);
                }
                request();
            }
        }

        // maxNum和urls.length取最小进行调用
        const times = Math.min(maxNum, urls.length);
        for(let i = 0; i < times; i++) {
    
    
            request();
        }
    })
}

测试代码

const urls = [];
for (let i = 1; i <= 20; i++) {
    
    
    urls.push(`https://jsonplaceholder.typicode.com/todos/${
      
      i}`);
}
concurrencyRequest(urls, 3).then(res => {
    
    
    console.log(res);
});

猜你喜欢

转载自blog.csdn.net/weixin_45678402/article/details/132825512
今日推荐