1. 程式人生 > 實用技巧 >Promise 實現併發請求限制

Promise 實現併發請求限制

Promise 併發限制


  • 併發請求限制,n個請求,每次最多隻能同時存在limit個請求,剩餘的在佇列中等待。

  • promiseAll 實現併發請求,n個請求,每次最多同時請求limit個,所有請求完成後處理資料。

併發請求限制

思路: 定義一個請求池,run 函式每次將等待佇列中任務加入到請求池中,直到塞滿或等待佇列空。再每個task執行完成後通過finally繼續執行run函式,addTask 為往等待佇列中新增任務,並執行run。


var startTime =new Date().getTime()

function taskPool(){
    this.tasks = [];
    this.pool = [];
    this.max = 2;
}


taskPool.prototype.addTask = function(task){
    this.tasks.push(task);
    this.run();
}

taskPool.prototype.run = function(){
    if(this.tasks.length ===0) return;
    let min = Math.min(this.tasks.length, this.max - this.pool.length);
    for(var i=0;i<min;i++){
        var currTask = this.tasks.shift();
        this.pool.push(currTask);
        currTask().then(res=>{
            console.log(new Date().getTime() - startTime);
        }).catch(err=>{

        }).finally(()=>{
            this.pool.splice(this.pool.indexOf(currTask), 1);
            this.run();
        })
    }
}

var pool = new taskPool();
for(let i=0;i<5;i++){
    pool.addTask(function(){
        return new Promise(resolve=>{
            setTimeout(()=>{
                resolve(i);
            },500);
        }).then(res=>{
            console.log('resolved' ,res);
        })
    })
}

/**

輸出:
resolved 0
500
resolved 1
500
resolved 2
1000
resolved 3
1000
resolved 4
1500

**/

promiseAll 併發請求限制


var startTime =new Date().getTime()

function asyncPool(array, limit){
    let index = 0;
    let res = [];
    let pool = [];

    let run = function() {
        if(index === array.length){
            return Promise.resolve();
        }

        let item = array[index++];
        let promise = Promise.resolve(item());

        res.push(promise);
        let e = promise.then(()=>{
            pool.splice(pool.indexOf(e), 1);
        })
        pool.push(e);
        console.log(`pool size : ${pool.length}`, pool);
        let r = Promise.resolve();
        if(pool.length >= limit){
            r = Promise.race(pool);
        }
        return r.then(()=>run());
    }
    return run().then(()=>{
        console.log(res);
        return Promise.all(res);
    });
}

var timeout = i => {
    return function () {
        return new Promise(resolve=>{
            setTimeout(()=>{resolve(i)}, i);
        })
    }
}


asyncPool([timeout(600),timeout(300),timeout(700),timeout(400),timeout(500)], 2, timeout).then(res=>{
    console.log(res);
    console.log(new Date().getTime() - startTime);
})

/**
輸出
[600, 300, 700, 400, 500]
1500

請求1 2 先發起; 1 2 起始時間 0
2請求完成 繼續請求3; 3 起始時間 300
1請求完成 繼續請求4; 4 起始時間 600
3請求完成 繼續請求5; 5 起始時間 1000
5請求完成,所有請求完成,此時時間 1500 
**/