Подтвердить что ты не робот

Nodejs несколько HTTP-запросов в цикле

Я пытаюсь сделать простой читатель каналов в node, и я столкнулся с проблемой с несколькими запросами в node.js. Например, я получил таблицу с URL-адресами примерно так:

urls = [
"http://url1.com/rss.xml",
"http://url2.com",
"http://url3.com"];

Теперь я хочу получить содержимое каждого URL-адреса. Первая идея заключалась в использовании for(var i in urls), но это не очень хорошая идея. лучшим вариантом было бы сделать это асинхронно, но я не знаю, как это сделать.

Любые идеи?

EDIT:

Я получил этот код:

var data = [];
for(var i = 0; i<urls.length; i++){
    http.get(urls[i], function(response){
    console.log('Reponse: ', response.statusCode, ' from url: ', urls[i]);
    var body = '';
    response.on('data', function(chunk){
        body += chunk;
    });

    response.on('end', function() {
        data.push(body);
    });
}).on('error', function(e){
    console.log('Error: ', e.message);
});
}

Проблема в том, что первая строка вызова "http.get..." для каждого элемента в цикле и после этого вызова response.on('data') вызывается и после этого response.on('end'). Это создает беспорядок, и я не знаю, как с этим справиться.

4b9b3361

Ответ 1

По умолчанию запросы node http являются асинхронными. Вы можете запускать их последовательно в своем коде и вызывать функцию, которая начнется, когда все запросы будут выполнены. Вы можете сделать это вручную (подсчитайте готовый vs начальный запрос) или используйте async.js

Это способ отсутствия зависимостей (ошибка проверки опущена):

var http = require('http');    
var urls = ["http://www.google.com", "http://www.example.com"];
var responses = [];
var completed_requests = 0;

for (i in urls) {
    http.get(urls[i], function(res) {
        responses.push(res);
        completed_requests++;
        if (completed_requests == urls.length) {
            // All download done, process responses array
            console.log(responses);
        }
    });
}

Ответ 2

Вам нужно проверить, что на end (событие завершения данных) было вызвано точное количество запросов... Вот рабочий пример:

var http = require('http');
var urls = ['http://adrianmejia.com/atom.xml', 'http://twitrss.me/twitter_user_to_rss/?user=amejiarosario'];
var completed_requests = 0;

urls.forEach(function(url) {
  var responses = [];
  http.get(url, function(res) {
    res.on('data', function(chunk){
      responses.push(chunk);
    });

    res.on('end', function(){
      if (completed_requests++ == urls.length - 1) {
        // All downloads are completed
        console.log('body:', responses.join());
      }      
    });
  });
})

Ответ 3

Я знаю, что это старый вопрос, но я думаю, что лучшим решением будет использование JavaScripts Promise.all()

const request = require('request-promise');
const urls = ["http://www.google.com", "http://www.example.com"];
const promises = urls.map(url => request(url));
Promise.all(promises).then((data) => {
    // data = [promise1,promise2]
} 

Ответ 4

Вы можете использовать любую библиотеку обещаний с реализацией ".all". Я использую библиотеку RSVP, достаточно простую.

var downloadFileList = [url:'http://stuff',dataname:'filename to download']
var ddownload = downloadFileList.map(function(id){
          var dataname = id.dataname;
          var url = id.url;
          return new RSVP.Promise(function(fulfill, reject) {
           var stream = fs.createWriteStream(dataname);
            stream.on('close', function() {
            console.log(dataname+' downloaded');
            fulfill();  
            });
          request(url).on('error', function(err) {
    console.log(err);
    reject();
  }).pipe(stream);
        });
        });      
        return new RSVP.hashSettled(ddownload);