2016-12-07 5 views
1

私のアプリケーションでは、私はと約束の配列は、ネットワークに並行してアクセスするが、いくつかの時間、私のアプリケーションがフルスピードを実行しているとき、多くのネットワークへのアクセスを約束していますが、私はどのようにして並列アクセスネットワークを制御できるか知りたいと思います。 これは、コードのサンプルです:Javascript - どのように多くの約束アクセスネットワークを制御する

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.all(Object.keys(ids).map(function(dp){ 
    return new Promise(function(resolve, reject){ 

     http.post({url: addr, form: { data: dp }}, function(err, res, body){ 
     if (err){ 
      reject(err) 
     }    
     resolve(body.xx); 
     }); 

    }); 
})).then(function(data){ 
     http.post({url: hostAddress, form: { data: data.x }}, function(err, res, body){ 
     ...... 
     resolve(body.xx); 
     });  
}); 
    }); 
})) 

ネットワーキングがたくさんあります。私は偉大な私は同時に2または3を許可することができます。ご協力いただきありがとうございます。

+0

https://github.com/ForbesLindesay/throatあなたはhttp://stackoverflow.com/a/を見てくださいどのように多くの同時約束は –

+0

を実行することができます制限できます38778887/1048572またはhttp://stackoverflow.com/a/39197252/1048572。 – Bergi

答えて

1

あなたが同時に飛行中のあるどのように多くの要求を制御するための同時実行オプションがあるBluebird's .map()使用することができます。FYI

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 
}); 

を、私はあなたの第二で何をしようとしていたものを理解していませんでしたhttp.post()data.xを参照している場合、dataが配列のためです。私はそのコードが実際に何をしようとしていたかを説明するためにあまりにも多くの疑似コードであると思う。http.post()


そうしないと、あなたが行うにはより多くのを持っていなくなるまで、あなたが別のを起動、たびに、最初は、その後、1つの仕上げを使用すると、Nリクエストを起動し、独自の同時実行制御をコーディングすることができます。ここでは、手動で同時実行制御を符号化する例を示します

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

それとも、あなたはこのようにそれを自分で書くことができます:

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

2番目の投稿で私は新しいリクエストを作成しています – dmx

+0

@dmx - しかし、擬似コードが正確ではないので、あなたがそれにフィードしようとしているものはわかりません。 「ここで結果を処理する」というところで提供したコードの結果を使用して、新しいリクエストを作成することができます。 – jfriend00

+0

@ jfriend00基本的に私はidsのリストを持っています。私はユーザーの情報を得るためのリクエストを行い、最後にユーザーの友人を募集します。 – dmx

1

これは、ライブラリを使用せずに、あなたの目標を達成するための一つの方法です。 makeMaxConcurrencyRequests()から返された約束の中でstartNew()関数が再帰的に呼び出され、すべてのIDを通過してmaxConcurrencyの現在の要求数を超過しない限り、新しい要求が送信されます。

各要求が完了すると、その戻りデータがreturnedData配列にプッシュされます。すべての要求が完了すると、約束はreturnedDataで解決されます。

私はこれをテストしていませんが、私の唯一の懸念は、要求が保留されている間にstartNew()が複数回連続して呼び出されることです。これが問題を引き起こした場合、startNew()を直ちに呼び出すのではなく、setTimeoutを使用して次の呼び出しを遅延させることができます。これは私のコードでコメントアウトされています。

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); 
      }); 
     }); 

    }); 
} 

使用法:

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 
}); 
関連する問題