這是一系列Nodejs實戰(zhàn)第一季后的整理筆記,為了快速查找及記錄
Node 功能的組織及重用
1.1.1、創(chuàng)建模塊
定義Node模塊
currency.js
/*exports 對象上只設(shè)定了兩個屬性。也就是說引入這個模塊的代碼只能訪問到 canadianToUS
和 USToCanadian 這兩個函數(shù)。而變量 canadianDollar 作為私有變量僅作用在 canadianToUS
和 USToCanadian 的邏輯內(nèi)部,程序不能直接訪問它。*/
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微調(diào)模塊的創(chuàng)建
module.exports返回一個Currency的構(gòu)造函數(shù)(類似于class)
/*
最終在程序里導(dǎo)出的是 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 異步編程技術(shù)
1.2.1 用回調(diào)處理一次性事件
回調(diào)是一個函數(shù),它被當(dāng)做參數(shù)傳給異步函數(shù)
實現(xiàn)功能
- 異步獲取存放在JSON文件中的文章標(biāo)題
- 異步獲取簡單的HTML模板
- 把那些標(biāo)題組裝到HTML頁面中
- 把HTML頁面發(fā)送給用戶
title.json
[
"node",
"利于",
"服務(wù)器"
]
template.html
<!doctype html>
<html>
<head></head>
<body>
<h1>Lastest Posts</h1>
<ul>
<!--會被替換為標(biāo)提-->
<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 用事件發(fā)射器處理重復(fù)性事件
echo服務(wù)器處理重復(fù)性事件的簡單案例
用on方法響應(yīng)事件
echo_server.js
var net = require('net');
var server = net.createServer(function(socket){
#當(dāng)讀取到新數(shù)據(jù)時處理的data事件 once 只響應(yīng)一次
socket.once('data',function(data){
socket.write(data);//數(shù)據(jù)被寫回到客戶端
});
});
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');
#設(shè)置
var channel = new events.EventEmitter();
channel.clients = {};
channel.subscriptions = {};
#綁定發(fā)射器
channel.on('join',function(id,client){
#添加join事件的監(jiān)聽器,保存用戶的client對象,以便程序可以將數(shù)據(jù)發(fā)送給用戶
this.clients[id] = client;
#連接人數(shù)
var num = "Welcome!\n" + 'Guest online:' + this.listeners('broadcast').length;
client.write('num is '+ num);
this.subscriptions[id] = function(senderId,message){
#忽略發(fā)出這一廣播數(shù)據(jù)的用戶
if(id != senderId){
this.clients[id].write(id +':'+ message);
}
}
#添加一個專門針對當(dāng)前用戶的broadcast事件監(jiān)聽器
this.on('broadcast',this.subscriptions[id]);
});
#創(chuàng)建一個在用戶斷開連接時能打掃戰(zhàn)場的監(jiān)聽器
channel.on('leave',function(id){
channel.removeListener('broadcast',this.subscriptions[id]);
channel.emit('broadcast',id,id+' has left the chat.\n');
});
#關(guān)閉聊天服務(wù) 但不關(guān)閉服務(wù)器
channel.on('shutdown',function(){
channel.emit('broadcast','',"Chat has shut down.\n");
channel.removeAllListeners('broadcast');
})
#增加監(jiān)聽器數(shù)量 channel 是事件發(fā)射器
channel.setMaxListeners(50);
#創(chuàng)建一個錯誤接聽器
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);
});
#用戶斷開連接時發(fā)出leave事件
client.on('close',function(){
channel.emit('leave',id);
});
});
server.listen(8888);
用匿名函數(shù)保留全局變量的值
/*異步 color在不斷變化 */
function asyncFunction(callback){
setTimeout(callback,200);
}
var color = 'blue';
asyncFunction(function(){
console.log('no function is color ' + color);
});
/*
* 解決方法
* 用javascript閉包可以“凍結(jié)”color的值
* 對asyncFunction的調(diào)用被封裝到以color為參數(shù)的匿名函數(shù)中
*/
(function(color){
asyncFunction(function(){
console.log("function is color " + color);
});
})(color);
var color = 'green';
1.3 異步邏輯順序化
用Nimble的流程控制
#安裝Nimble
npm install nimble
Nimble工具實現(xiàn)串行
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 實現(xiàn)串行化流程控制
將預(yù)先需要按流程執(zhí)行的任務(wù)添加到數(shù)組中
/*
* 串行執(zhí)行
* 并行下載后 串行執(zhí)行歸檔
*/
var flow = require('nimble');
var exec = require('child_process').exec;
//下載文件輔助函數(shù)
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);
}
//按照順序執(zhí)行串行化任務(wù) 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){
//創(chuàng)建遞歸文件
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 并行流程控制
/*
* 并行化流程控制
* 計算文件中單詞出現(xiàn)的次數(shù)
*/
var fs = require('fs');
var completedTakes = 0;
var takes = [];
var wordCounts = {};
var fileDir = './text';
//所有的任務(wù)都完成后
function checkIfComplate(){
completedTakes++;
if(completedTakes == takes.length){
for(var index in wordCounts){
console.log(index + ': '+wordCounts[index]);
}
}
}
//計算文件中出現(xiàn)的單詞數(shù)
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]();
}
});
水平一般,能力有限。隨手記憶~~~~