学学nodejs

Nodejs编程基础

2016-11-19  本文已影响62人  十亩鱼塘

这是一系列Nodejs实战第一季后的整理笔记,为了快速查找及记录

Node 功能的组织及重用

1.1.1、创建模块

定义Node模块
currency.js

/*exports 对象上只设定了两个属性。也就是说引入这个模块的代码只能访问到 canadianToUS
和 USToCanadian 这两个函数。而变量 canadianDollar 作为私有变量仅作用在 canadianToUS
和 USToCanadian 的逻辑内部,程序不能直接访问它。*/
var canadianDollar = 0.91;
functon roundTwoDecimals(amount){
  return Math.round(amount * 100)/100;
}
exports.canadianToUS = funtion(canadian){
  return roundTwoDecimals(candian * canadianDollar);
}
exports.USToCanadian = function(us){
  return roundTwoDecimals(us/canadianDollar);
}

引入一个模块
test-currency.js

var currency = require('./currency');
console.log(currency.canadianToUS(50));
console.log(currency.USToCanadina(30));

1.1.2 用module.exports微调模块的创建

module.exports返回一个Currency的构造函数(类似于class)

/*
最终在程序里导出的是 module.exports 。 exports 只是对 module.exports 的一个全
局 引 用 , 最 初 被 定 义 为 一 个 可 以 添 加 属 性 的 空 对 象 。 所 以 exports.myFunc 只 是
module.exports.myFunc 的简写
*/
var Currency = function(canadianDollar){
  this.canadianDollar = canadianDollar;
}
Currency.prototype.roundTwoDecimals = function(amount){
  return Math.round(amount * 100) / 100;
}
Currency.prototype.canadianToUS = function(canadian){
  return this.roundTwoDecimals(canadian * this.canadianDollar);
}
Currency.prototype.USToCanadian = function(us){
  return this.roundTwoDecimals(us / this.canadianDollar);
}
module.exports = exports = Currency;

1.2 异步编程技术

1.2.1 用回调处理一次性事件
回调是一个函数,它被当做参数传给异步函数
实现功能

[
  "node",
  "利于",
  "服务器"
]

template.html

<!doctype html>
<html>
  <head></head>
  <body>
    <h1>Lastest Posts</h1>
    <ul>
      <!--会被替换为标提-->
      <li>%</li>
    </ul>
  </body>
</html>

blog_recent.js

var http = require('http');
var fs = require('fs');
var server = http.createServer(function(req,res){
    getTitles(res);
}).listen(3000);
function getTitles(res){
    fs.readFile('./title.json',function(err,data){
        if(err) return hadError(err,res);
        getTemplate(JSON.parse(data.toString()),res);
    });
}
function getTemplate(titles,res){
    fs.readFile('./template.html',function(err,data){
        if(err) return hadError(err,res);
        formatHtml(titles,data.toString(),res);
    })
}
function formatHtml(titles,tmpl,res){
    var html = tmpl.replace('%',titles.join('<li></li>'));
    res.writeHead(200,{'Content-Type':'text/html'});
    res.end(html);
}
function hadError(err,res){
    console.log(err);
    res.end('Server Error');
}

1.2.2 用事件发射器处理重复性事件
echo服务器处理重复性事件的简单案例
用on方法响应事件
echo_server.js

var net = require('net');
var server = net.createServer(function(socket){
  #当读取到新数据时处理的data事件 once 只响应一次
  socket.once('data',function(data){
      socket.write(data);//数据被写回到客户端
    });
});
server.listen(8888);

运行 node echo_server.js
新打终端 telnet 127.0.0.1:8888

Paste_Image.png

简易聊天室
easy_chat.js

var events = require('events');
var net = require('net');
#设置
var channel = new events.EventEmitter();
channel.clients = {};
channel.subscriptions = {};
#绑定发射器
channel.on('join',function(id,client){
  #添加join事件的监听器,保存用户的client对象,以便程序可以将数据发送给用户
  this.clients[id] = client;
  #连接人数
  var num = "Welcome!\n" + 'Guest online:' + this.listeners('broadcast').length;
  client.write('num is '+ num);
  this.subscriptions[id] = function(senderId,message){
    #忽略发出这一广播数据的用户
    if(id != senderId){
      this.clients[id].write(id +':'+ message);
    }
  }
  #添加一个专门针对当前用户的broadcast事件监听器
  this.on('broadcast',this.subscriptions[id]);
});
#创建一个在用户断开连接时能打扫战场的监听器
channel.on('leave',function(id){
  channel.removeListener('broadcast',this.subscriptions[id]);
  channel.emit('broadcast',id,id+' has left the chat.\n');
});
#关闭聊天服务 但不关闭服务器
channel.on('shutdown',function(){
  channel.emit('broadcast','',"Chat has shut down.\n");
  channel.removeAllListeners('broadcast');
})
#增加监听器数量 channel 是事件发射器
channel.setMaxListeners(50);
#创建一个错误接听器
var server = net.createServer();
server.on('connection',function(client){
  var id = client.remoteAddress + ':' + client.remotePort;
  #连接时
  console.log('connect success');
  channel.emit('join',id,client);
  client.on('data',function(data){
    data = data.toString();
    if(data == "shutdown\r\n"){
      channel.emit('shutdown');
    }
    channel.emit('broadcast',id,data);
  });
  #用户断开连接时发出leave事件
  client.on('close',function(){
    channel.emit('leave',id);
  });
});
server.listen(8888);

用匿名函数保留全局变量的值

/*异步 color在不断变化 */
function asyncFunction(callback){
  setTimeout(callback,200);
}
var color = 'blue';
asyncFunction(function(){
  console.log('no function is color ' + color);
});
/*
* 解决方法
* 用javascript闭包可以“冻结”color的值
* 对asyncFunction的调用被封装到以color为参数的匿名函数中
*/
(function(color){
  asyncFunction(function(){
    console.log("function is color " + color);
  });
})(color);
var color = 'green';

1.3 异步逻辑顺序化

用Nimble的流程控制

#安装Nimble
npm install nimble

Nimble工具实现串行

var flow = require('nimble');
flow.series([
    function(callback){
        setTimeout(function(){
            console.log('I exec first.');
            callback();
        },1000);
    },
    function(callback){
        setTimeout(function(){
            console.log('I exec second.');
            callback();
        },500);
    },
    function(callback){
        setTimeout(function(){
            console.log('I exec third.');
            callback();
        },100);
    }
]);

1.3.2 实现串行化流程控制
将预先需要按流程执行的任务添加到数组中

/*
* 串行执行
* 并行下载后 串行执行归档
*/

var flow = require('nimble');
var exec = require('child_process').exec;

//下载文件辅助函数
function downloadNodeVersion(version,destination,callback){
    var url = "http://nodejs.org/dist/node-v" + version + ".tar.gz";
    var filepath = destination + '/' + version + '.tgz';
    exec('curl '+url+' > '+ filepath,callback);
}
//按照顺序执行串行化任务 series 串行的
flow.series([
    function(callback){
        //parallel 平行的 并列的
        flow.parallel([
            function(callback){
                console.log('Downloading Node v0.4.6....');
                downloadNodeVersion('0.4.6','/tmp',callback);
            },
            function(callback){
                console.log('Downloading Node v0.4.7....');
                downloadNodeVersion('0.4.7','/tmp',callback);
            }
        ],callback);
    },
    function(callback){
        //创建递归文件
        console.log('Creating archive of download files');
        exec('tar cvf node_distros.tar /tmp/0.4.6.tgz /tmp/0.4.7.tgz',
        function(error,stdout,stderr){
            console.log('All done!');
            callback();
        }
    )
}
]);

1.3.3 并行流程控制

/*
* 并行化流程控制
* 计算文件中单词出现的次数
*/
var fs = require('fs');
var completedTakes = 0;
var takes = [];
var wordCounts = {};
var fileDir = './text';

//所有的任务都完成后
function checkIfComplate(){
  completedTakes++;
  if(completedTakes == takes.length){
    for(var index in wordCounts){
      console.log(index + ': '+wordCounts[index]);
    }
  }
}

//计算文件中出现的单词数
function countWordsInText(text){
  var words = text.toString().toLowerCase().split(' ');
  console.log(words);

    for(var index in words){
      word = words[index];
      if(word){
        wordCounts[word] = (wordCounts[word])?wordCounts[word]+1:1;
      }

    }
}

//读取文件
fs.readdir(fileDir,function(err,files){
  if(err) throw err;
  for(var index in files){
    var take = (function(file){
      return function(){
        fs.readFile(file,function(err,text){
          if(err) throw err;
          countWordsInText(text);
          checkIfComplate();
        });
      }
    })(fileDir +'/'+ files[index]);
    //加入排序中
    takes.push(take);
  }
  for(var index in takes){
    takes[index]();
  }
});

水平一般,能力有限。随手记忆~~~~

上一篇 下一篇

猜你喜欢

热点阅读