Nodejs開發指南-筆記

第三章 異步式I/O與事件編程
3.1 npm install -g supervisor
  supervisor app.js 當後臺修改代碼後,服務器自動重啓,生效修改的代碼,不用手動中止/啓動
3.2 單線程異步I/O
  減小了多線程的開銷,對於操做系統,建立線程的開銷很大,需分配內存、列入調度。同時線程切換時
  須要內存換頁,CPU的緩存被清空,切換回來時,須要從新從內存中讀取信息,破壞了數據的局部性。
  異步讀取文件:javascript

var fs = require('fs')

fs.readFile('test.txt','utf-8',function(err,data){
if(err){
console.log(err);
}
else console.log(data);
})

console.log('end');

輸出:
end;
content of the test.txt

 

3.3模塊和包
3.3.一、模塊
  什麼是模塊:
    一個文件就是一個模塊。
  建立模塊:
    exports和require實現
  舉例說明java

//module.js
var name;
exports.setName = function(thyname){
name = thyname;
}

exports.getName = function(){
console.log(name);
}


//getnodule.js
var module = require('./module')

module.setName('xxx')
module.getName();

對於對象的封裝:
//hello.js
function Hello(){
var name;
this.setName = function(thyname){
name = thyname;
};
this.sayHello = function(){
console.log("Hello "+name);
}
}

module.exports = Hello;

//gethello.js
var Hello = require('./hello')

var hello = new Hello();
hello.setName("xxx");
hello.sayHello();  

3.3.二、包
  將一個文件夾封裝成一個模塊,即所謂的包
     (1)做爲文件夾的模板
  一、創建一個somepackage文件夾
  二、在somepackage下創建index.js文件 (必須是index.js)
  三、文件中寫入node

exports.hello=function(){
console.log('Hello World');
};
在somepackage文件夾外創建一個getpackage.js文件
寫入
var somepackage=require('./somepackage');
somepackage.hello();
3.2.2 package.json
在主目錄下建立package.json,寫入:
{
"main":"./lib/interface.js"
}
在主目錄中創建lib子文件夾,並在其中建立interface.js文件,在文件中寫入

exports.hello=function(){
console.log('Hello Node.js');
};
運行上面的getpackage.js獲得相同的結果。

Node.js在調用某個包時,會首先檢查包中package.json中的main字段,將其做爲包的接口模塊,若是main不存在,會嘗試尋找index.js或者index.node做爲包的接口
3.4nodejs的包管理器npm
  npm install [包名]
  npm install -g [包名]//全局目錄安裝
  建立的全局模式的包,不能直接require使用,須要建立全局連接
    npm link [包名]
    ./node_moudles/[包名] -> /usrt/local/lib/node_moudles/expresslinux

3.5npm包的發佈
  一、npm init 填寫好package.json信息
  二、npm adduser 按照提示填寫帳號信息,用於之後維護包
  三、npm publish 發佈包
  打開瀏覽器 http://npmjs.org/能夠查找到,並且在世界商任意一臺主機上,均可以用npm install [包名]來安裝你發佈的包
3.6調試
3.6.1命令行調試
  在設置斷點的代碼處添加debugger
  node debug app.js
  進入調試界面,help查看調試命令
3.6.2遠程調試
  //在一個終端裏(不加port,默認是5858)
  node --debug-brk[=port] app.js
  或 node --debug[=port] app.js
  //在另外一個終端中
  node debug 127.0.0.1:5858或 node debug 127.0.0.1:[port]
3.6.3node-inspector調試
  npm install -g node-inspector
  //運行腳本
    node --debug-brk=5858 app.js
  //啓動node-inspector
    $ node-inspector
  //打開瀏覽器
    http://127.0.0.1:8080/debug?port=5858express

第四章nodejs核心模塊
4.1全局對象
  永遠使用var定義變量,避免引入全局變量,由於你全局變量會污染明明空間。
4.1.1 process.argv命令行參數數組
  第一個參數是node 第二個參數是腳本文件名,第三個參數是運行參數
4.1.2 process.nextTick(callback)npm

  爲事件循環設置一項任務,將複雜的任務,拆分紅一個個較小的事件編程

舉例說明:
function doSomething(callback){
compile()
callback()
}

doSomething(function onEnd){
compute()
}
改進後
function doSomething(callback){
compile()
process.nextTick(callback)
}

doSomething(function onEnd){
compute()
}
改進後的程序會把上面耗時的操做拆分位兩個事件,減小每一個事件的執行時間,提升時間響應效率。

4.2經常使用工具util
4.2.1 util.inspect將人已對象轉換成字符串。
  util.inspect(object.[showHidden],[depth],[color])
    showHidden可選參數,若是是true,輸出更過隱藏信息
    depth可選參數,最大遞歸層數,默認2,指定爲null表示不想遞歸層數,完整遍歷。
    color可選參數,true表示輸出格式以ANSI顏色編碼,終端顯示更漂亮。
4.3事件驅動events(最重要的模塊)
4.3.1事件發射器json

 

events.EventEmitter 時間發射和時間監聽
var events = require('events')
var emitter = new events.EventEmitter()

emitter.on('someEvent',function(arg1,arg2){
console.log('listen ',arg1,arg2)
})

emitter.emit('someEvent','byvoid',1991)
輸出
listen byvoid 1991

 

4.4文件系統fs
4.4.1 fs.readFile()異步讀取文件數組

fs.readFile('filename','utf-8',function(err,data){
if(err){
console.log(err)
}
else{
console.log(data)
}
})

4.4.2 fs.readFileSync(filename,[encoding])同步讀取文件
4.4.3 fs.open(path,flags,[mode],[callback(err,fd)])
  path:文件路徑, flags:r,r+,w,w+,a,a+ 兩個必選參數
  mode:用於建立文件時給文件的指定權限,默認是0666
4.4.4 fs的其餘經常使用函數:
  1)讀取文件
    異步:fs.readFile(filename,[encoding],[callback(err,data)])
    同步:fs.readFileSync(filename,[encoding])
  2)寫入文件(清空原有的)
    異步:fs.writeFile(filename,data,[encoding],[callback(err)])
    同步:fs.writeFileSync(filename,data,[encoding])
  3)追加寫入文件
    異步:fs.appendFile(filename,data,[encoding],[callback(err)])
    同步:fs.appendFileSync(filename,data,[encoding])
  4)刪除文件
    異步fs.unlink(path,[callbacl(err)])
    同步:fs.unlinkSync(path)
  5)建立目錄
    異步:fs.mkdir(path,[mode],[callback(err)])
    同步:fs.mkdirSync(path,[mode])
  6)刪除目錄
    異步:fs.rmdir(path,[callback(err)])
    同步:fs.rmdirSync(path)
  7)讀取目錄(讀取目錄下的全部文件,輸出一個數組)
    異步:fs.readdir(path,[callback(err)])
    同步:fs.readdirSync(path)
  8)獲取文件真實路徑
    異步:fs.realpath(filename,[callback(err,files)])
    同步:fs.realpathSync(filename)
  9)改名
    異步:fs.rename(path1,path2,[callback(err)])
    同步:fs.renameSync(path1,path2)
  10)更改權限
    異步:fs.chmod(path,mode,[callback(err)])
    同步:fs.chmodSync(path,mode)
  11)更改全部權
    異步:fs.chown(path,uid,gid,[callback(err)])//uid和gid爲整形,linux下運行id命令能夠查詢
    同步:fs.chownSync(path,uid,gid)瀏覽器

第六章 Nodejs進階話題
6.1 加載緩存
  nodejs不會重複加載,這是由於nodejs經過文件名緩存全部加載過的文件模塊,因此之後再放問到時,就不會重複加載了。require後只需加載一次
6.2 Nodejs應用部署
6.2.1 不支持故障恢復
  當程序發生錯誤時,後臺直接垮掉
6.2.2 沒有日誌輸出
  解決方法:Express支持另種運行模式:開發模式和產品模式。前者用於調試,後者用於部署。
  只需設置NODE_ENV變量便可,NODE_ENV = production實現產品模式,node app.js能夠看到
  Express server listening on port 3000 in production
  在app.js的最上方添加一下代碼,實現日誌打印

var fs = require('fs');

var accessLogfile = fs.createWriteStream('access.log',{flags:'a'});
var errorLogfile = fs.createWriteStream('error.log',{flags:'a'});
app.use(express.logger({stream: accessLogfile}))
//對於錯誤日誌,須要單獨實現錯誤響應

app.config('production',function(){
app.error(function(err,req,res,next){
var meta = '['+ new Date() +']' + req.url+'\n';
errorLogfile.write(meta+err.stack+'\n');
next();
})
})

6.2.3 沒法利用多核提升性能(單線程)
  解決方法:cluster模塊。cluster的功能是生成與當前進程相同的子進程,並容許子進程和父進程之間共享端口。
    調用cluster模塊,將主進程生成若干工做進程。
6.2.4 獨佔端口
  解決方法:利用ngix,經過反向代理實現nodejs虛擬主機
  下面舉例配置文件

server {
listen 80;
server_name mysite.com;
location /{
proxy_pass http://localhost:3000;
}
}

該配置文件的功能是,監聽訪問mysite.com 80端口的請求,並將多有的請求轉發給localhost:3000
6.2.5 須要手動啓動(重啓服務器的化)
  解決方法:編寫開機腳本
6.3 nodejs不適合作什麼
6.3.1 不適合計算密集型程序
6.3.2 不適合單用戶多任務應用。
  node適合解決大量併發請求,單用戶不存在併發請求。
6.3.3 不適合邏輯十分複雜的事物
  node更善於處理邏輯簡單但訪問頻繁的任務。

附錄A JavaScript的高級特性
A-一、做用域
  js的做用域是經過函數來定義的。變量的搜索由函數內向函數外擴展

var scop = "global"

var f = function(){
console.log(scop);//輸出undefined
scop = "f";
}

注:js訪問未定義或着定義了但未初始化的變量,都是undefined
A-二、對象
js只有對象,對象就是對象,不是類的實例
js中的對象不是基於類實現的,而是基於原型實現的。
一、var foo = {} //即爲對象
  foo.prop_1 = 'bar'
二、使用對象初始化器建立對象

var foo = {
prop1:'bar',
prop2:function(){
}
}

三、使用構造函數建立對象

function User(name, uri){
this.name = name;
this.uri = uri;
this.display = function(){
return this.name;
}
}
var someuser = new User('name','http://baidu.com')

四、上下文對象(call)
call能夠實現繼承。

user = {
name:"xxxx",
uri:'baudu.com',
display: function(words){
console.log(this.name+" "+words) 
}
}

var foo = {
name:'foobar'
}
user.display.call(foo,'hello')
輸出: foobar hello

A-三、原型
利用原型來初始化對象

function Foo(){}
Foo.prototype.name = "user"
Foo..prototype.getName = function() {
return this.name
};
var foo = new Foo()
foo.getName()//輸出user

舉例說明構造函數內建立屬性和原型定義成員函數的區別

function Foo(){
this.prop = "prop";
this.getProp = function(){
return this.prop
}
}
Foo.prototype.name = "user"
Foo..prototype.getName = function() {
return this.name
};

var foo1 = new Foo()
var foo2 = new Foo()
console.log(foo1.getProp ==foo2.getProp)//false
console.log(foo1.getName ==foo2.getName)//true

構造函數內定義的任何屬性,包括函數在內都被重複構建,同一個構造函數產生的兩個對象不共享實例。
因此儘可能用原型定義成員函數,減小開銷。
儘可能在構造函數內定義通常成員,尤爲是數組或對象,由於原型中定義的成員是多個實例共享的。
B、Nodejs編程規範

  一、兩個空格作縮進
  二、分號作換行符
  三、var定義變量 絕對不能使用賦值隱式定義的變量(全局變量,空間污染),確保每一個語句定義一個變量,(不能定義多個變量,之間用','分割)
  四、變量名和屬性名(駝峯式命名空間)
  五、對於函數定義,() {}之間要有一個空格
  六、贊成使用單引號
  七、等號儘可能使用===
  八、命名函數
    回調函數和構造函數,儘可能給函數命名。
    對於回調函數,Nodejs和第三方模塊約定第一個參數是err
  九、對象定義    全部成員函數,儘可能用原型進行定義,屬性在構造函數內定義,而後對構造函數用new進行對象的建立

相關文章
相關標籤/搜索