基于Promise实现一个限制并发请求的函数

基于Promise实现一个限制并发请求的函数

1. 首先模拟一下请求方法

let getRequestFn = function(time){
    return ()=>{
        return new Promise((resolve,reject)=>{
            setTimeout(() => {
                resolve(time)
            }, time);
        })
    }
} // 执行函数可返回一个自定义请求事件的函数,用来模拟请求

2. 实现一个限制并发数量的方法
首先我们可以思考一下如何可以限制并发,无非就是用一个循环来判断当前的执行个数,如果小于限制个数就再次发送请求,很多小伙伴可能会写出这样的代码,比如:

function request(tasks,pool){
    pool = pool || 5;
    let results = [];
    let running = 0;
    while(tasks.length > 0){ // 如果还有请求未执行
        if(running < pool) { // 如果小于并发次数 就再取出请求方法执行
            let task = tasks.shift();
            running++; 
            task().then(result => {
                results.push(result); // 将执行结果存入数组
                running --; // 当前执行个数减一
            });
        }
    }
}

我们很容易忽略一个问题,js是单线程的,函数执行过程中如果遇到异步任务,那么这个异步任务会退出主线程,存放到任务队列中等待执行,当主线程任务为空时才会执行异步任务,所以我们可以看到,代码中的running --; 这个操做是无法被操作到的。因为while一直在运行,导致异步任务无法获得主线程的执行。

使用递归实现限制并发数量的方法
// 要保证同时同时有pool个请求执行

function createRequest(tasks=[],pool){
    pool = pool || 5; //限制并发的数量
    let results = [];
    let running = 0; // 当前运行个数
    let resultsLength = tasks.length; // 用来判断最后的是否全部成功
    return new Promise((resolve,reject)=>{
        next();
        function next(){
            while(running < pool && tasks.length){ // 这个wile循环保证 一直有pool个请求在进行
            running++;
            let task = tasks.shift();
            task().then(result => {
                results.push(result);
            }).finally(()=>{
                running--;
                next();
            })
            }
            if(results.length === resultsLength) { // 全部执行结束
                resolve(results);
            }
        }
    })
}

我们使用一个next函数来保证每次可以有怕pool个请求函数在执行,并且超过两个时就可以退出循环,这样可以执行到异步任务,使得running--;并且再次执行next()用来执行请求的函数,最后当全部请求完毕以后返回results,当然本函数没有处理请求失败的问题,大家有兴趣以可以添加。

  1. 测试
//创建模拟请求任务
let tasks = [getRequestFn(4000),getRequestFn(2000),getRequestFn(2000),getRequestFn(2000)];
// 发送请求 并发数为2
console.time();
createRequest(tasks,2).then((value)=>{
    console.log(value)
    console.timeEnd();
})
// 输出
[ 2000, 4000, 2000, 2000 ]
default: 6.016s
// 可以看到执行了6s 因为同时只有两个请求可以发送 2000, 4000 =》 2000 结束以后 又执行一个2000的 最后 4000结束 执行2000的 一共6s
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值