2015-08-01 29 views
9

Geniş bir URL dizisini yükleyen bir uygulama ile bir kontrol akışı sorunu yaşıyorum. Caolan Async ve NPM istek modülünü kullanıyorum.Async paralel HTTP isteği

Sorunum, işlevin kuyruğa eklendiği anda HTTP yanıtının başlamasıdır. İdeal olarak kuyruğumu oluşturmak ve sadece kuyruk başladığında HTTP isteklerini yapmaya başlamak istiyorum. Aksi takdirde, geri çağrılar, kuyruk başlamadan önce ateşlemeye başlar - kuyruğun zamanından önce bitmesine neden olur.

var request = require('request') // https://www.npmjs.com/package/request 
    , async = require('async'); // https://www.npmjs.com/package/async 

var myLoaderQueue = []; // passed to async.parallel 
var myUrls = ['http://...', 'http://...', 'http://...'] // 1000+ urls here 

for(var i = 0; i < myUrls.length; i++){ 
    myLoaderQueue.push(function(callback){ 

     // Async http request 
     request(myUrls[i], function(error, response, html) { 

      // Some processing is happening here before the callback is invoked 
      callback(error, html); 
     }); 
    }); 
} 

// The loader queue has been made, now start to process the queue 
async.parallel(queue, function(err, results){ 
    // Done 
}); 

Buna saldırmanın daha iyi bir yolu var mı?

cevap

17

(ES5 ile) problemlidir ve beklenmedik sonuçlar doğurabilir (sizin durumunuzda, yanlış URL alınabilir).

Bunun yerine, async.map() kullanmayı düşünün:

async.map(myUrls, function(url, callback) { 
    request(url, function(error, response, html) { 
    // Some processing is happening here before the callback is invoked 
    callback(error, html); 
    }); 
}, function(err, results) { 
    ... 
}); 

Verilen Eğer 1000+ url en almak zorunda olduğunu, async.mapLimit() da dikkate değer olabilir.

+0

Mükemmel çalışıyor. Teşekkürler. – ChrisRich

+0

ES6'da bu daha az sorunlu olabilir mi? – xShirase

+0

@xShirase ES6, '' '' '' bloğuna '' kapsamı '' olan '' let' kullanarak blok izlemeye sahiptir; var olan kodda, 'var' ile, 'myUrls [i] ' – robertklep

7

Eğer promises ve ES7async/await yararlanmak Bluebird ve Babel kullanmaya başlamak için istekli iseniz aşağıdakileri yapabilirsiniz:

asenkron çağrıları ile kombine for döngüler kullanarak
let Promise = require('bluebird'); 
let request = Promise.promisify(require('request')); 

let myUrls = ['http://...', 'http://...', 'http://...'] // 1000+ urls here 

async function load() { 
    try { 
    // map myUrls array into array of request promises 
    // wait until all request promises in the array resolve 
    let results = await Promise.all(myUrls.map(request)); 
    // don't know if Babel await supports syntax below 
    // let results = await* myUrls.map(request)); 
    // print array of results or use forEach 
    // to process/collect them in any other way 
    console.log(results) 
    } catch (e) { 
    console.log(e); 
    } 
} 
+1

node.js ES7 yazabilmek için, Cudos benim projem ES5 temel aldığı için bu cevabı kullanılamaz ve tüm programı – ChrisRich

+1

yeniden yazmak istemiyorum ... ama! – ChrisRich

+3

Ayrıca 'Promise.all' yerine' myUrls.map (request) 'yazabilirsiniz. –

0

Farklı bir hatanın sonuçlarını deneyimlediğinizden oldukça eminim. Sıraya alınmış işlevleriniz değerlendirildiğinde, yeniden tanımlandım. Bu, ilk URL'leri kaçırdığınız gibi görünmesine neden olabilir. Fonksiyonları sıralarken biraz kapatmayı deneyin.

var request = require('request') // https://www.npmjs.com/package/request 
    , async = require('async'); // https://www.npmjs.com/package/async 

var myLoaderQueue = []; // passed to async.parallel 
var myUrls = ['http://...', 'http://...', 'http://...'] // 1000+ urls here 

for(var i = 0; i < myUrls.length; i++){ 
    (function(URLIndex){ 
     myLoaderQueue.push(function(callback){ 

      // Async http request 
      request(myUrls[URLIndex], function(error, response, html) { 

       // Some processing is happening here before the callback is invoked 
       callback(error, html); 
      }); 
     }); 
    })(i); 
} 

// The loader queue has been made, now start to process the queue 
async.parallel(queue, function(err, results){ 
    // Done 
}); 
+0

Cevabım doğru olabilir, ama robertklep daha iyidir. 5 dakika önce göndermiş olsaydı ya da 5 dakika daha yavaş olsaydım. – trex005

+0

Evet tanıdık sorun :-) BTW, 'myUrls [i]' 'myUrls [URLIndex]' olmalıdır. – robertklep

+0

Dang, çok hızlı gidiyordum ... Bu yüzden düzenlenmiş. – trex005