Javascript - how to control how many promises access network in parallel

前端 未结 2 464
天涯浪人
天涯浪人 2020-11-27 23:32

in my application, I have and array of promises that access network in parallel, but some times, when my app is running full speed, my network slows down, due to many promi

相关标签:
2条回答
  • 2020-11-28 00:14

    This is one way of achieving your aim without using a library. Within the promise returned from makeMaxConcurrencyRequests(), the startNew() function is recursively called, sending new requests until we have been through every id, and without exceeding a current request count of maxConcurrency.

    When each request completes, its return data is pushed into the returnedData array. When all requests are completed, the promise is resolved with returnedData.

    I haven't tested this, but looking at it my only concern is that startNew() is going to be called multiple times in quick succession while requests are pending. If this causes issues then rather than immediately calling startNew(), we could use setTimeout to delay the next invocation - this is commented out in my code.

    function makeMaxConcurrencyRequests(ids, maxConcurrency) {
        return new Promise(function(resolve, reject) {
            let i = 0, currentlyRunning = 0, returnedData = [];
            function startNew() {        
                while (i < ids.length && currentlyRunning <= maxConcurrency) {
                    makeRequest(ids[i++]).then(function(data) {
                        returnedData.push(data);
                        currentlyRunning--;
                        startNew();
                    }).catch(function(err) {
                        reject(err);
                    });
                    currentlyRunning++;
                }
                if (i >= ids.length && currentlyRunning === 0) {
                    resolve(returnedData);
                }
                startNew();
                // setTimeout(startNew, 200);           
            }
        }
    }
    
    function makeRequest(id) {
        return new Promise(function(resolve, reject){
            http.post({url: addr, form: { data: dp }}, function(err, res, body){
                if (err){
                    reject(err)
                } 
    
                http.post({url: hostAddress, form: { data: body.xx }}, function(err2, res2, body2){
                    if(err2) {
                        reject(err2);
                    }
                    resolve(body2.xx);
               }); 
           });
    
       });
    }
    

    Usage:

    var ids = {1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 6: 56, 7: 7, 8: 8, 5:6 };
    var maxConcurrency = 3;
    makeMaxConcurrencyRequests(Object.keys(ids), maxConcurrency)
    .then(function(data) {
        // do something with data
    }).catch(function(error) {
        // do something with error
    });
    
    0 讨论(0)
  • 2020-11-28 00:23

    You can use Bluebird's .map() which has a concurrency option to control how many requests are in-flight at the same time:

    const Promise = require('bluebird');
    const http = Promise.promisifyAll(require('http');
    
    var ids = {1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 6: 56, 7: 7, 8: 8, 5:6 }; // this is random 
    
    Promise.map(Object.keys(ids).map(function(dp){
        return  http.post({url: addr, form: { data: dp }).then(function(body) {
            return body.xx;
        });
    }), {concurrency: 2}).then(function(results) {
        // process results here
    });
    

    FYI, I didn't understand what you were trying to do with your second http.post() because you where referencing data.x when data is an array. I think the code is a bit too much pseudo-code to illustrate what you were really trying to do with that second http.post().


    Otherwise, you can code your own concurrency control where you fire up N requests initially and then each time one finishes, you fire up another until you have no more to do. Here's an example of coding the concurrency control manually:

    Fire off 1,000,000 requests 100 at a time

    Or, you could write it yourself like this:

    const http = require('http');
    
    function httpPost(options) {
        return new Promise(function(resolve, reject) {
            http.post(options, function(err, res, body) {
                if (err) {
                    reject(err);
                } else {
                    resolve(body);
                }
            });
        });
    }
    
    // takes an array of items and a function that returns a promise
    function mapConcurrent(items, maxConcurrent, fn) {
        let index = 0;
        let inFlightCntr = 0;
        let doneCntr = 0;
        let results = new Array(items.length);
        let stop = false;
    
        return new Promise(function(resolve, reject) {
    
            function runNext() {
                let i = index;
                ++inFlightCntr;
                fn(items[index], index++).then(function(val) {
                    ++doneCntr;
                    --inFlightCntr;
                    results[i] = val;
                    run();
                }, function(err) {
                    // set flag so we don't launch any more requests
                    stop = true;
                    reject(err);
                });
            }
    
            function run() {
                // launch as many as we're allowed to
                while (!stop && inflightCntr < maxConcurrent && index < items.length) {
                    runNext();
                }
                // if all are done, then resolve parent promise with results
                if (doneCntr === items.length) {
                    resolve(results);
                }
            }
    
            run();
        });
    }
    
    var ids = {1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 6: 56, 7: 7, 8: 8, 5:6 }; // this is random 
    
    
    mapConcurrent(Object.keys(ids), 2, function(item, index) {
        return httpPost({url: addr, form: {data: item}}).then(function(body) {
            return body.xxx;
        });
    }).then(function(results) {
        // array of results here
    }, function(err) {
        // error here    
    });
    
    0 讨论(0)
提交回复
热议问题