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

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

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

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

PHPz
PHPz

学习是最好的投资!

全員に返信(3)
伊谢尔伦

原生版,用results和counter两个变量维护状态,保持顺序靠那个idx变量实现

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;
  });
});

能够完成需求,但容错、扩展、可读性一塌糊涂

request+bluebird版

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);
  });

题目没说并行请求还是串行,这里都是并行的,串行的话反正天然保持顺序闭着眼睛打印就行

いいねを押す +0
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)
})
いいねを押す +0
伊谢尔伦

一般以前我碰上这种情况都会果断的选择回调来写的,代码大概是下面这个样子:

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);

但是自从接触了 Promise 之后感觉这样写异步要顺畅多了,所以慢慢的也转变过来了,代码大概是这个样子的:

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());
いいねを押す +0
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート