2017-02-05 3 views
-1

Это учебное упражнение learnyounode 9 на node.js. У меня возникли проблемы с пониманием того, почему мой код не распечатывает данные по порядку.learnyounode - Juggling Async - разный порядок

let http = require('http'), 
    bl = require('bl'), 
    urlArray = [process.argv[2], process.argv[3], process.argv[4]] 
    results = [] 
    //counter = 0; 

function collectData(i) { 
    http.get(urlArray[i], (res) => { 
     res.pipe(bl((err, data) => { 
      if (err) { 
       return console.log(err); 
      } 
      data = data.toString(); 
      results[i] = data; 
      //counter++; 

      //if (counter === 3) { 
       if (results.length === 3) { 
       results.forEach((result) => { 
        console.log(result); 
       }) 
      } 
     })) 
    }) 
} 

for (let i = 0; i < urlArray.length; i++) { 
    collectData(i); 
} 

Цикл for должен начинаться с первого URL-адреса и до конца доходить до конца. Из моего понимания, что бы ни происходило в текущей итерации цикла, необходимо решить, чтобы цикл переместился на следующую итерацию. Однако результаты кажутся случайными. Если я запустил свое решение в командной строке, иногда результаты в порядке, а иногда и нет.

Редактировать: Это мое текущее решение, которое работает. Я добавил переменную счетчика и поместил http-запрос в функцию.

+0

* «все, что происходит в текущей итерации цикла должны решить для петли, чтобы перейти к следующей итерации» * - нет, это именно то, что асинхронный код. * нет * делаю. Это очень * определение * асинхронного. – JJJ

+0

@JJJ Означает ли это, что все для циклов в node.js не обязательно запускаются по порядку? – James

+0

Нет, это означает, что асинхронные методы не обязательно разрешаются по порядку. HTTP-запросы отправляются в порядке, вызываемые вызовы вызываются всякий раз, когда они получают ответ. – JJJ

ответ

0

Причина, по которой вы получаете разные результаты при каждом прогоне, заключается в том, что функция get http реализована асинхронно (асинхронно). Вы делаете запросы в правильном порядке, но веб-сервер на URL-адресе get-response отвечает не сразу.

Так в основном, если у вас есть два адреса для вызова:

http://stackoverflow.com

http://google.com

Вы называете их в таком порядке, но Google есть хорошее время отклика этот запуск, как 10мс, StackOverflow требуется немного дольше, чем 20 мс, сначала вызывается функция обратного вызова для google, а затем функция обратного вызова для stackoverflow.

Время отклика может отличаться от каждого пробега, поэтому вы испытываете разные результаты при каждом запуске.

Это ваша обратный вызов функция:

res.pipe(bl((err, data) => { 
    if (err) { 
     return console.log(err); 
    } 
    data = data.toString(); 
    console.log(data); 
} 
+0

Я думал что, поскольку он был в цикле for, это не имело бы значения.Из комментария JJJ и вашего ответа кажется, что программа должна знать, когда все будет готово. Это то, что я сделал, но он все еще не работает. Результаты [i] = данные; if (results.length === 3) { for (let j = 0; j James

+0

Не могли бы вы опубликовать его, как вы это сделали сейчас? Потому что я не знаю, как вы обрабатываете переменную итерации (i) функции обратного вызова – Merschi

+0

Извините за задержку. Обновлено. – James

0

Вся проблема с переменными «I» и асинхронными вызовами. С этой конкретной логикой у вас нет контроля над значением i из-за асинхронных вызовов.

Чтобы понять проблему с вашим кодом, напечатайте console.log после строки: результаты [i] = данные;

Это мое решение проблемы:

var http = require('http'); 

var count =3; 
var contentResults = []; 


function hitRequests(i) { 
    http.get(process.argv[i+1],function(response){ 
     response.setEncoding('utf8'); 

     var entireContent=''; 

     response.on('data', function(chunk){ 
      entireContent += chunk; 
     }); 

     response.on('end', function(chunk){ 

      contentResults[i] = entireContent; 
      count --; 

      if(count <= 0) { 
       printAll(); 
      } 

     }); 

    }).on('error',function(e){ 

     console.log('error'+e); 
    }); 
} 

for(i=1;i<=3;i++) { 
    hitRequests(i); 
} 

function printAll() { 
    contentResults.forEach(function(result){ 
     console.log(result); 
    }); 
} 
+0

@james Попробуйте понять, как переменная i ведет себя на итерации. Но у вас не будет той же проблемы, когда вы вызываете другую функцию. –

+0

Я редактировал мое решение выше. У меня есть еще один вопрос. Если я не использую счетчик и просто имею условие if (results.length === 3), это не сработает. С счетчиками вы увеличиваете/уменьшаете после того, как данные были добавлены в массив результатов. Разве это не будет работать, если я сравниваю длину массива результатов? Я просто ничего не получаю? – James

+0

Можете ли вы опубликовать обновленный код, чтобы я мог получить больше ясности. –