node.js - 求解一道node小题目
PHPz
PHPz 2017-04-17 11:31:23
0
3
401

在nodeschool上学习时遇到的问题:learnyounode里的第九题:

写一个小程序,要求输入三个参数url,使用该程序模拟三次get请求分别从这三个url获取数据,全部返回后打印到控制台上。要求:打印出的响应数据要和三个url参数的顺序一样,即打印出的第一条应该是第一个url返回的数据,url由命令行参数提供(process.argv)。

因为node是异步的,所以不知道应该如何控制这个输出的顺序,求帮忙!

PHPz
PHPz

学习是最好的投资!

reply all(3)
伊谢尔伦

The native version uses two variables, results and counter, to maintain the state, and maintain the order by relying on the idx variable

jsvar http = require('http');
var args = process.argv;

if(args.shift() === 'node') args.shift();

if(process.argv.length !== 3) {
  console.log('must input 3 url, got', args);
  process.exit();
}

var results = [];
var counter = 0;
args.forEach(function(url, idx) {
  http.get(url, function(res) {
    res.on('data', function (chunk) {
      if(!results[idx]) {
        results[idx] = '';
      }
      results[idx] += chunk;
    }).on('end', function() {
      counter++;

      if (counter === args.length) {
        results.forEach(function(res, i) {
          console.log(args[i], res);
        });
      }
    });
  }).on('error', function(e) {
    throw e;
  });
});

It can fulfill the requirements, but fault tolerance, expansion and readability are a mess

request+bluebird version

var request = require('request');
var Promise = require('bluebird');
var prequest = Promise.promisify(request);

var args = process.argv;

if(args.shift() === 'node') args.shift();

if(process.argv.length !== 3) {
  console.log('must input 3 url, got', args);
  process.exit();
}

Promise.all(args.map(function(url) {
  return prequest(url);
}))
  .each(function(result) {
    var response = result[0];
    console.log(response.request.href, response.body);
  })
  .catch(function(e) {
    console.error(e);
  });

The title doesn’t say whether the request is parallel or serial. It’s all parallel here. If it’s serial, just keep the order and print with your eyes closed.

PHPzhong
楼主可以使用这个异步库[async][1]

var async = require('async');
var http = require('http');
var urls = ['www.baidu.com', 'www.qq.com', 'www.haosou.com']

async.map(urls, function (url, callback) {
    var data = "";
    http.get({host: url}, function (res) {
        res.setEncoding('utf-8');
        res.on('data', function (chunck) {
            data += chunck;
        });

        res.on('end', function () {
            callback(null, data);
        });
    }).on('error', function (error) {
        return callback(error);
    });
}, function(error, result){
    if(error)
        console.log(error);
    else
        console.log(result)
})
伊谢尔伦

Usually when I encounter this kind of situation, I will decisively choose to write callbacks. The code probably looks like the following:

var http = require("http"),
    urls = process.argv,
    datas = [];

if( urls.shift() === "node" ) urls.shift();
function getHTML( url, callback ) {
    http.get( url, function( res ) {
        var result = "";
        res.on( "data", function(chunk) { result += chunk; })
           .on( "end", function() { callback( result ); });
   })
}

(function get( p ) {
    if( p === urls.length ) return last();
    getHTML( urls[p], function(res) {
        datas.push( res )
        get( ++p );
    })
    function last() {
        datas.forEach(function(d){ console.log(d) })
    }
})(0);

But since I came into contact with Promise, I feel that writing asynchronously this way is much smoother, so I gradually changed it. The code probably looks like this:

var Promise = require("promise").Promise,
    http = require("http");

var urls = process.argv;
if( urls.shift() === "node" ) urls.shift();

function getHTML( url ) {
    return new Promise(function( resolve, reject ) {
        http.get( url, function( res ) {
            var result = "";
            res.on( "data", function(chunk) { result += chunk })
               .on( "end", function() { resolve(result) })
               .on( "error", function() { reject(result) })
       })
    })
}

urls.map(getHTML).reduce(function(seq, html) {
    return seq.then(function(){return html}).then(function(res){
        console.log( res );
    })
}, Promise.resolve());
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template