这是一系列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 用回调处理一次性事件
回调是一个函数,它被当做参数传给异步函数
实现功能
- 异步获取存放在JSON文件中的文章标题
- 异步获取简单的HTML模板
- 把那些标题组装到HTML页面中
- 把HTML页面发送给用户
title.json
[
"node",
"利于",
"服务器"
]
template.html
Lastest Posts
- %
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(''));
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
简易聊天室
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]();
}
});
水平一般,能力有限。随手记忆~~~~