如何使learnyounode#9兼顾异步工作

时间:2016-01-03 03:53:56

标签: javascript node.js asynchronous ecmascript-6

我正在尝试通过nodeschool的learnyounode。

  

此问题与上一个问题(HTTP COLLECT)相同   你需要使用http.get()。但是,这次你会   提供了三个URL作为前三个命令行参数。

     

您必须收集每个提供给您的完整内容   URL并将其打印到控制台(stdout)。你不需要打印出来   长度,只是作为字符串的数据;每个网址一行。问题是   您必须按照与URL相同的顺序打印出来   作为命令行参数提供给你。

这是我的代码:

var bl = require('bl');
var http = require('http');

var urls = [process.argv[2], process.argv[3], process.argv[4]]
var dataArray = [];
var count = 0;


for (var i = 0; i <= urls.length-1; i++) {
  http.get(urls[i], function(response){ 
    response.setEncoding('utf8').pipe(bl(function (err, data) { 
      dataArray[i] = data.toString();
      count++;
      if (count==2){
        dataArray.forEach(function(item){
          console.log(item);
        })
      }
    }));
  });

};

当我尝试验证时:

  1. 实际:“她会像牛奶一样平坦的女性伴侣。抓住我们一个疯子作为战斗员。”
  2. 预计:“让我们得到一些帕尔马来注意pav。她会是正确的平板而不用担心他会有一个巨大的饼干。让我们得到一些g fla的flamin她将是正确的丁字裤。”

  3. ACTUAL:“”

  4. 预计:“跟你一起养一只狗就会生病了。他有一个巨大的yobbo血腥的十字架作为一个bonza。”

  5. ACTUAL:

  6. 预计:“她会像牛奶酒吧那样正确的女性伴侣。给我们一个疯子作为战斗员。”

  7. ACTUAL:

  8. 预期:“”
  9. 我在这里做错了什么?

2 个答案:

答案 0 :(得分:1)

您编写的脚本以在命令行传入的最后一个参数结束。

在调试中使用节点4.2.4运行:

node debug test.js google.com facebook.com yahoo.com

使用 c 继续。

repl在调试时访问上下文。

s 进入函数。

每次循环以“yahoo.com”结束。

For循环使用节点是异步的,并且如复制链接中所建议的那样,您需要bind或在i计数器上创建一个闭包。但是,随着循环迭代方式的改变:

var bl = require('bl');
var http = require('http');

var urls = [process.argv[2], process.argv[3], process.argv[4]]
var dataArray = [];
var count = 0;

urls.forEach(function(url, i){
  console.log(url)
  var options = {
    hostname: url,
    port: 80
  }
  http.get(options, function(response){
    console.log(options, response.statusCode)
    response.setEncoding('utf8').pipe(bl(function (err, data) {
      dataArray[i] = data.toString();
      count++;
      console.log(options, data)
    }));
  })  
  .on('error', function(e) {
    console.log("Got error: " + e.message);
  });
})

结果:

< google.com
< facebook.com
< yahoo.com
< { hostname: 'google.com', port: 80 } 301
< { hostname: 'google.com', port: 80 } <Buffer 3c 48 54 4d 4c 3e 3c 48 45 41 44 3e 3c 6d 65 74 61 20 68 74 74 70 2d 65 71 75 69 76 3d 22 63 6f 6e 74 65 6e 74 2d 74 79 70 65 22 20 63 6f 6e 74 65 6e ... >
< { hostname: 'yahoo.com', port: 80 } 301
< { hostname: 'yahoo.com', port: 80 } <Buffer 3c 48 54 4d 4c 3e 0a 3c 48 45 41 44 3e 0a 3c 54 49 54 4c 45 3e 45 72 72 6f 72 3c 2f 54 49 54 4c 45 3e 0a 3c 2f 48 45 41 44 3e 0a 0a 3c 42 4f 44 59 20 ... >
< { hostname: 'facebook.com', port: 80 } 302
< { hostname: 'facebook.com', port: 80 } <Buffer >

注意我添加了options,因为我没有将“http://”作为我收到的网址的一部分包含在内:

< google.com
< facebook.com
< yahoo.com
< Got error: connect ECONNREFUSED 127.0.0.1:80
< Got error: connect ECONNREFUSED 127.0.0.1:80
< Got error: connect ECONNREFUSED 127.0.0.1:80

请注意:

或使用承诺:

var bl = require('bl');
var http = require('http');

var urls = [process.argv[2], process.argv[3], process.argv[4]]
var dataArray = [];
var count = 0;

for (var i = 0; i <= urls.length-1; i++) {
  console.log(i)
  // Or you can use a promise which will create a closure with
  // the callback passed in

  // uncomment this promise to see the difference
  // Promise.resolve(i).then(function(i){
    console.log(i, urls)
    http.get({hostname: urls[i], port:80}, function(response){ 
      response.setEncoding('utf8').pipe(bl(function (err, data) { 
          dataArray[i] = data.toString();
          count++;
          console.log(urls[i], i, data)
      }));
    }).on('error', function(e){
      console.log(e.message)
    });
  // });
};

没有承诺:

< 0
< 0 [ 'http://google.com',
<   'http://facebook.com',
<   'http://yahoo.com' ]
< 1
< 1 [ 'http://google.com',
<   'http://facebook.com',
<   'http://yahoo.com' ]
< 2
< 2 [ 'http://google.com',
<   'http://facebook.com',
<   'http://yahoo.com' ]
< undefined 3 <Buffer 3c 68 74 6d 6c 3e 0d 0a 3c 68 65 61 64 3e 3c 74 69 74 6c 65 3e 34 30 30 20 42 61 64 20 52 65 71 75 65 73 74 3c 2f 74 69 74 6c 65 3e 3c 2f 68 65 61 64 ... >
< undefined 3 <Buffer 3c 68 74 6d 6c 3e 0d 0a 3c 68 65 61 64 3e 3c 74 69 74 6c 65 3e 34 30 30 20 42 61 64 20 52 65 71 75 65 73 74 3c 2f 74 69 74 6c 65 3e 3c 2f 68 65 61 64 ... >
< undefined 3 <Buffer 3c 68 74 6d 6c 3e 0d 0a 3c 68 65 61 64 3e 3c 74 69 74 6c 65 3e 34 30 30 20 42 61 64 20 52 65 71 75 65 73 74 3c 2f 74 69 74 6c 65 3e 3c 2f 68 65 61 64 ... >

承诺:

< 0
< 1
< 2
< 0 [ 'http://google.com',
<   'http://facebook.com',
<   'http://yahoo.com' ]
< 1 [ 'http://google.com',
<   'http://facebook.com',
<   'http://yahoo.com' ]
< 2 [ 'http://google.com',
<   'http://facebook.com',
<   'http://yahoo.com' ]
< http://google.com 0 <Buffer 3c 68 74 6d 6c 3e 0d 0a 3c 68 65 61 64 3e 3c 74 69 74 6c 65 3e 34 30 30 20 42 61 64 20 52 65 71 75 65 73 74 3c 2f 74 69 74 6c 65 3e 3c 2f 68 65 61 64 ... >
< http://facebook.com 1 <Buffer 3c 68 74 6d 6c 3e 0d 0a 3c 68 65 61 64 3e 3c 74 69 74 6c 65 3e 34 30 30 20 42 61 64 20 52 65 71 75 65 73 74 3c 2f 74 69 74 6c 65 3e 3c 2f 68 65 61 64 ... >
< http://yahoo.com 2 <Buffer 3c 68 74 6d 6c 3e 0d 0a 3c 68 65 61 64 3e 3c 74 69 74 6c 65 3e 34 30 30 20 42 61 64 20 52 65 71 75 65 73 74 3c 2f 74 69 74 6c 65 3e 3c 2f 68 65 61 64 ... >

答案 1 :(得分:1)

您想检查count == 3是否有3个网址。

你也不想在这样的循环中使用一个函数。 在这种情况下,每次执行匿名函数时i的值为3 ... 这就是为什么您只输出第三个网址的预期值的原因。

这是最新例子:JavaScript closure inside loops – simple practical example

通过将函数包装在一个新函数中,您可以确保i正是您想要的那样。

这应该有效:

var bl = require('bl');
var http = require('http');

var urls = [process.argv[2], process.argv[3], process.argv[4]];
var dataArray = [];
var count = 0;


function juggle (i) {
  http.get(urls[i], function(response) {
    response.setEncoding('utf8').pipe(bl(function(err, data) {
      dataArray[i] = data.toString();
      count++;
      if (count == 3) {
        dataArray.forEach(function(item) {
          console.log(item);
        });
      }
    }));
  });
}

for (var i = 0; i < 3; i++) {
  juggle(i)
}