Promise解决并发请求

5,705 阅读1分钟

Promise解决并发请求

引言: 美团二面的场景题,当时没做出来,现在来好好解决一下这个问题。

场景: 现在提供10个id和请求函数(请求返回promise对象),现在要求你设置一个并发数(假设为3),达到并发设置效果。

let request = function(id){
    return new Promise((resolve,reject)=>{
        //随机一个执行时间
        let time = Math.floor(10000*Math.random());
        console.log(`id为${id}开始请求,预计执行时间${time/1000}`)
        setTimeout(()=>{
            resolve(id);
        },time)
    }).then((id)=>{
        console.log(`id为${id}的请求进行逻辑处理`)
        return id;
    })
}
let idArray = [0,1,2,3,4,5,6,7,8,9,10];

意思就是先发并发数的请求,然后每有一个请求回调结束接着发呗,保证同一时刻最多三个请求在处理过程中。(现在一想就是这个意思,下午想歪了)

Promise版本

思路: 设置一个pool池放置这些请求返回的promise,然后发max个(构造函数发送),函数中每次都把promise push到pool中,然后进行then回调的注册,里边首先把promise拿出来,然后拿数组id,判断进行递归。

function run(){
    //启动函数,直接将max个请求进行执行
    for (let i=0;i<max;i++){
        send(request(idArray.shift()));
    }
}
function send(promise){
    pool.push(promise);
    promise.then((res)=>{
        console.log(`id${res}的请求已经处理完毕,当前并发${pool.length}`);
        //移除已处理的请求
        pool.splice(pool.indexOf(promise),1);
        let id = idArray.shift();
        if (id !==undefined){
            send(request(id));
        }
    })
}
run();

总之就是先启动,后序then方法进行递归调用,注意pool的控制。

Async+Promise.race

思路:利用async写成同步代码,用Promise.race(pool) 来控制,每次pool中有resolve的promise(处理完的请求),就可以继续发送新请求了。

async function run(){
    for (let i=0;i<idArray.length;i++){
        let promise = request(idArray[i]);
        promise.then((res)=>{
            console.log(`id${res}的请求已经处理完毕,当前并发为${pool.length}`);
            pool.splice(pool.indexOf(promise),1);
        })
        pool.push(promise);
        //这里是重点,当满了就阻塞
        if (pool.length==max){
            await Promise.race(pool);
        }
    }
}
run();

非常简洁,很好理解,不用then里面放递归了。