目錄
- 模塊創(chuàng)建以及使用
- 文件模塊的使用
- IO鍵盤交互
- URL解析
一烹看、模塊創(chuàng)建以及使用
- 什么是模塊
模塊和文件是一 一對應的墙歪,一個模塊就是一個js文件听系,Node.js提供了exports和require兩個對象,其中exports是模塊公共的接口虹菲,require用于從外部獲取一個模塊的接口,即獲取模塊的exports對象掉瞳。想要在外部用自定義模塊中的方法exports方法暴露出去毕源,通過require引入模塊再調用其方法。 - 模塊的分類
- 核心模塊
如http陕习、fs霎褐、path等该镣,引用《深入淺出Node.js》中的一段話
核心模塊部分在Node源代碼的編譯過程中冻璃,編譯進了二進制執(zhí)行文件。在Node進程啟動時损合,部分核心模塊就被直接加載進內存中省艳,所以這部分核心模塊引入時,文件定位和編譯執(zhí)行這兩個步驟可以省略掉嫁审,并且在路徑分析中優(yōu)先判斷跋炕,所以他的加載速度是最快的。
第三方模塊
通過NPM安裝的模塊都會放入到node_modules目錄下律适,在引用模塊時和核心模塊類似辐烂,require方法只需寫模塊名一就可以,不需要路徑捂贿。Node在查找這個模塊時會現(xiàn)在本級目錄下查看是否有node_modules目錄纠修,若有看其內是否有相應的模塊,若沒有會去父目錄查找厂僧,以此類推扣草,就像是JavaScript的原型鏈和作用域鏈的查找方式。所以這類模塊的查找會耗時最多,加載最慢德召。創(chuàng)建模塊
第一種方式
//mymodule.js
//使用exports向外部暴露方法
var name;
exports.setName=function(isname) {
name = isname;
}
exports.sayNanme=function (){
console.log('hello my name is '+name);
}
//getmymodule.js
var myModule =require('./mymodule');
myModule.setName('AngelaMuller');//調用模塊中方法設置屬性
myModule.sayNanme();//調用方法
使用:
muller@ubuntu:~/node$ node getmymodule.js
hello my name is AngelaMuller
第二種方式
//mymodule.js
module.exports = function (name){
this.name = name;
this.sayhello = function(){
console.log('hello world白魂!'+this.name);
}
};
//getmymodule.js
var person = require('./mymodule');
var oneper = new person('AngelaMuller');
oneper.sayhello();
使用:
muller@ubuntu:~/node$ node getmymodule.js
hello world!AngelaMuller
- 單次加載
上面的例子有點類似創(chuàng)建一個對象上岗,但實際上和對象又有本質的區(qū)別福荸,因為require不會重復加載模塊,也就是說無論調用多少次require肴掷,獲取的模塊都是同一個 - 覆蓋exports
有時我們知識想把一個對象封裝到模塊中敬锐,例如
定義模塊:singleobejct.js
引入模塊使用:getSingleObject.js
繁瑣:exports.hello=hello;
引入:require("./singleobject").hello;
簡易:module.exports=hello;
exports本身僅僅是一個普通的空對象,即{}呆瞻,它是專門用來聲明接口
定義模塊:singleobejct.js
function hello(){
var name;
this.setName=function(thyName){
name=thyName;
}
this.sayHello=function(){
console.log('hello '+name);
}
}
//exports.hello=hello;
module.exports=hello; // 定義的方法添加 (簡單的方式)
引入模塊使用:getSingleObject.js
var hello=require('./singleobject');
var he=new hello();
he.setName('marico'); //實例化第一個實例
he.sayHello();
var he2=new hello(); //實例化第二個實例
he2.setName('yfc');
he2.sayHello()
結果輸出:
[root@localhost nodejs]# node getSingleObject.js
hello marico
hello yfc
繁瑣:exports.hello=hello; //使用這種方式加載在對象中時台夺,在調用使用時比較繁瑣
引入:require("./singleobject").hello;
二、文件操作
node.js模塊是文件操作的封裝痴脾,它提供了文件的讀取颤介,寫入,更名赞赖,刪除滚朵,遍歷目錄,鏈接POSIX文件系統(tǒng)操作前域。與其他模塊不同的是辕近,fs模塊中所有的操作都提供了異步和同步兩個版本,例如匿垄,讀取文件內容函數(shù)異步方法移宅,readFile(),同步方法readFileSync().
- 同步方式的文件系統(tǒng)調用會導致阻塞,由于Node.js是單線程的椿疗,直到文件調用完成后漏峰,控制權才會被放回主線程,這也就導致了后臺其他線程池中的很多線程不能夠執(zhí)行变丧,從而導致Node.js中一定程度的性能問題芽狗。因此應該盡可能的減少使用同步方式的文件系統(tǒng)的方法調用。
- 異步調用會被主線程放置在事件隊列中以備隨后運行痒蓬,這使得調用能夠融入Node.js中的事件模型童擎。但在執(zhí)行代碼時,就會變得有點棘手攻晒,因為事件并不能在預期的時候完成顾复,這就需要有一個callback函數(shù)來規(guī)定當調用完成時需要完成的事。(這里可以去深入了解下Node.js的事件隊列)
簡單讀取
fs.readFile(path,[options],callback);
fs.readFildSync(path,[options]);非簡單讀取
fs.read(fd,buffer,offset,length,position,callback);
fs.readSync(fd,buffer,offset,length,position);流式讀取
fs.createReadStream(path,[options]);fs模塊的其他方法
驗證文件/目錄路徑的存在性
fs.exists(path,callback);
fs.existsSync(path);
注: 同步方法返回true/false鲁捏,異步方法callback僅僅只有一個err對象表示是否刪除成功芯砸。
同步讀取
//引入fs模塊
var fs=require('fs');
fs.readFile('content.txt','UTF-8',function(err,data){
if(err){
console.log(err);
}else{
console.log(data);
}
});
//沒有回調函數(shù)
try{
var data=fs.readFileSync('content.txt','UTF-8');
console.log(data+"同步式讀取");
}catch(e){
console.log(e)
}
content.txt 內容
Node.js的文件系統(tǒng)的Api AngelaMuller
輸出結果:
muller@ubuntu:~/node$ node mymodule.js
Node.js的文件系統(tǒng)的Api AngelaMuller同步式讀取
Node.js的文件系統(tǒng)的Api AngelaMuller
異步讀取文件與readFile相同,而讀取到的文件內容會以函數(shù)返回值的形式返回,如果有錯誤發(fā)生假丧,fs將拋出異常双揪,你需要try和catch捕獲并處理異常。
Node.js from fs.readFileSync() to fs.readFile()
其他方法請查看官方API https://nodejs.org/dist/latest-v4.x/docs/api/fs.html
三包帚、 IO交互
什么是IO交互
簡單點是Node.js的控制臺輸入輸出渔期,I 是input 可讀輸入流 ,O是output 可輸出流渴邦,Node.js也有如同C++和Java的標準輸入輸出進行交互疯趟。
- 輸入設備
輸入設備是人向計算機輸入信息的設備,常用的輸入設備有:
(1)鍵盤---人向計算機輸入信息最基本的設備谋梭;
(2)鼠標器----一種光標指點設備信峻;
(3)觸摸屏----一種坐標定位設備,常用于公共查詢系統(tǒng)瓮床。 - 輸出設備
輸出設備是直接向人提供計算機運行結果的設備盹舞,常用的輸出設備有:
(1)顯示器---計算機的主要輸出設備,它與鍵盤一起構成最基本的人機對話環(huán)境;
(2)打印機---打印機為用戶提供計算機信息的硬拷貝纤垂。常用的打印機有:擊打式矾策、噴墨式和激光打印機。
什么是Readline
Readline是Node.js里實現(xiàn)標準輸入輸出的封裝好的模塊峭沦,通過這個模塊我們可以以逐行的方式讀取數(shù)據(jù)流。
使用require("readline")可以引用模塊逃糟。
如何使用Readline
// 引入readline模塊
const readline = require('readline');
//創(chuàng)建readline接口實例
const rl = readline.createInterface({
input: process.stdin, //監(jiān)聽的可讀流 (必填)
output: process.stdout //逐行讀群鹩恪(Readline)數(shù)據(jù)要寫入的可寫流(可選)
});
rl.setPrompt('What is your name ? > ');//設置提示符
rl.prompt(); //為用戶輸入準備好逐行讀取(Readline),讓用戶有新的地方輸入
rl.on('line', function (str) {
console.log('my name is : '+str);
});
// close事件監(jiān)聽
rl.on("close", function(){
// 結束程序
console.log('Have a great day!');
process.exit(0);// 結束程序
});
/* v0.10.44 版本似乎有問題 v4.5.0案例
rl.on('line', (line) => {
var str = line.trim();
console.log('my name is : '+str);
rl.prompt();
}).on('close', () => {
console.log('Have a great day!');
process.exit(0);
});
*/
在close事件的監(jiān)聽里绰咽,我們執(zhí)行了process.exit(0)來使程序退出的操作菇肃,因為readline模塊只要一開始獲取用戶輸入就不會結束,必須使用這種直接的方式來結束程序取募。
輸入與輸出實例
// 引入readline模塊
var readline = require('readline');
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.on('line', function(line){
switch(line.trim()) {
case 'copy':
console.log("復制");
break;
case 'hello':
rl.write("Write");
console.log('world!');
break;
case 'close':
rl.close();
break;
default:
console.log('沒有找到命令琐谤!');
break;
}
});
rl.on('close', function() {
console.log('bye bye');
process.exit(0);
});
'line'事件,這個事件就是在用戶輸完一行玩敏,按下回車后就會觸發(fā)的事件斗忌,它會將用戶輸入的數(shù)據(jù)通過回調函數(shù)傳回來,可在此方法里處理用戶輸入的數(shù)據(jù)
命令行輸入與輸出
const readline = require('readline');
const rl = readline.createInterface(process.stdin, process.stdout);
rl.setPrompt('OHAI> ');
rl.prompt();
rl.on('line', (line) => {
switch(line.trim()) {
case 'hello':
console.log('world!');
break;
default:
console.log('Say what? I might have heard `' + line.trim() + '`');
break;
}
rl.prompt();
}).on('close', () => {
console.log('Have a great day!');
process.exit(0);
});
四旺聚、URL解析
1.URL模塊為URL的解析工具
var url = require('url');
var urlString = 'http://user:pass@best.bluepay.asia:90/p/a/t/h?query=string#hash';
var result = url.parse(urlString);
console.log(result);
//第二個可選參數(shù)設置為true時 query: { query: 'string' },
輸出結果:
muller@ubuntu:~/node$ node url.js
Url {
protocol: 'http:',
slashes: true,
auth: 'user:pass',
host: 'best.bluepay.asia:90',
port: '90',
hostname: 'best.bluepay.asia',
hash: '#hash',
search: '?query=string',
query: 'query=string',
pathname: '/p/a/t/h',
path: '/p/a/t/h?query=string',
href: 'http://user:pass@best.bluepay.asia:90/p/a/t/h?query=string#hash' }
- href 屬性會被忽略
- protocol無論是否有末尾的 : (冒號)织阳,會同樣的處理 這些協(xié)議包括 http, https, ftp, gopher, file 后綴是
://
(冒號-斜杠-斜杠). 所有其他的協(xié)議如 mailto, xmpp, aim, sftp, foo, 等 會加上后綴 : (冒號) - auth 如果有將會出現(xiàn).
- hostname 如果 host 屬性沒被定義,則會使用此屬性.
- port 如果 host 屬性沒被定義砰粹,則會使用此屬性.
- host 優(yōu)先使用唧躲,將會替代 hostname 和port
- pathname 將會同樣處理無論結尾是否有/ (斜杠)
- search 將會替代 query屬性
- query (object類型; 詳細請看 querystring) 如果沒有 search,將會使用此屬性.
- search 無論前面是否有 ? (問號),都會同樣的處理
- hash無論前面是否有# (井號, 錨點),都會同樣處理
2.queryString 模塊
提供了實用程序來處理查詢字符串
-
querystring.stringify(obj, [sep], [eq])
將JSON對象格式化為查詢字符串格式的字符串弄痹,默認的分隔符為:“&”和“=”饭入,具體可以看一下以下代碼.
querystring.stringify({ foo: 'bar', baz: ['qux', 'quux'], corge: '' })
// returns 'foo=bar&baz=qux&baz=quux&corge='
querystring.stringify({foo: 'bar', baz: 'qux'}, ';', ':')
// returns 'foo:bar;baz:qux'
// Suppose gbkEncodeURIComponent function already exists,
// it can encode string with `gbk` encoding
querystring.stringify({ w: '中文', foo: 'bar' }, null, null,
{ encodeURIComponent: gbkEncodeURIComponent })
// returns 'w=%D6%D0%CE%C4&foo=bar'
-
querystring.parse(str, [sep], [eq], [options])
根據(jù)“&”和“=”將字符串進行分割,反序列化為JSON對象肛真,而options包含的maxKeys默認設置為1000谐丢,如果將其設置為0則表示沒這個限制.
querystring.parse('foo=bar&baz=qux&baz=quux&corge')
// returns { foo: 'bar', baz: ['qux', 'quux'], corge: '' }
// Suppose gbkDecodeURIComponent function already exists,
// it can decode `gbk` encoding string
querystring.parse('w=%D6%D0%CE%C4&foo=bar', null, null,
{ decodeURIComponent: gbkDecodeURIComponent })
// returns { w: '中文', foo: 'bar' }
-
querystring.escape,querystring.unescape
這兩個內置方法毁欣,分別在上述兩個方法的內置使用庇谆,如果有需要分別格式化和解碼URL字符串。
3. QueryString模塊和Url模塊之間的關系
url.parse(string).query
|
url.parse(string).pathname |
| |
| |
------ -------------------
http://localhost:8888/start?foo=bar&hello=world
--- -----
| |
| |
querystring(string)["foo"] |
|
querystring(string)["hello"]
4. 獲取靜態(tài)資源
完整實例(根據(jù)不同的url地址請求不同的文件)
const ip = '192.168.1.223';//主機IP
const port = 3000;//端口號
//引入的組建模塊 http凭疮、url饭耳、fs
const http = require('http');
const urls = require('url');
const fs = require('fs');
//實例化一個服務容器
var server = new http.Server();
//監(jiān)聽一個端口
server.listen(port , ip);
//注冊一個事件處理的on方法
server.on('request' , function(req , res){
//獲取請求的url地址
var url = urls.parse(req.url);
//console.log(url.pathname);
//根據(jù)path路徑來讀取不同的模板文件
switch( url.pathname ){
//顯示首頁
case '' || '/':
//讀取文件內容
fs.readFile('./index.html',function( error, content){
if(error){
//如果有錯誤時,顯示錯誤信息
funError();
}else{
//正確時瀏覽器輸出模板文件的內容
funAuccess(res,content);
}
});
break;
//顯示列表頁面
case '/list':
fs.readFile('./list.html',function( error, content){
if(error){
funError(res , error);
}else{
funAuccess(res,content);
}
});
break;
//顯示詳情頁
case '/show':
fs.readFile('./show.html',function( error, content){
if(error){
funError(res , error);
}else{
funAuccess(res,content);
}
});
break;
//獲取靜態(tài)資源的頁面 如:css\js
default:
//獲取文件名
var filename = url.pathname.substring(1);
//獲取文件名對應的類型值
var type = getAllType( filename.substring(filename.lastIndexOf('.')+1));
//測試所用
//console.log(type);
//讀取靜態(tài)資源的頁面
fs.readFile(filename , function( error, content){
if(error){
funError(res , error);
}else{
res.writeHead(200,{'Content-Type' : type});
res.write(content);
res.end();
}
});
break;
}
});
//錯誤提示的函數(shù)
function funError(response , error){
response.writeHead(400,{'Content-Type':'text/plain;charset="utf-8"'});
response.write(error.message);
response.end();
}
//正確時輸出文件內容的函數(shù)
function funAuccess(response,cont){
response.writeHead(200,{'Content-Type':'text/html;charset="utf-8"'});//頭信息
response.write(cont);//模板文件內容
response.end();
}
//定義文件類型的函數(shù)
function getAllType(code){
var type = '';
switch(code){
case 'html':
type = 'text/html;charset=utf-8';
break;
case 'js':
type = 'application/javascript/html;charset=utf-8';
break;
case 'css':
type = 'text/css;charset=utf-8';
break;
case 'text':
type = 'text/plain;charset=utf-8';
break;
case 'manifest':
type = 'text/cache-manifest;charset=utf-8';
break;
default:
type = 'application/octet-stream';
break;
}
return type;
}