Node.js 其實就是藉助谷歌的 V8 引擎,將桌面端的 js 帶到了服務器端,它的出現我將其歸結爲兩點:javascript
安裝的話基本是分爲 Windows 和 POSIX(爲*unx 和 Mac等系統的統稱)。php
大均可以從相應的包管理器上進行安裝(非大神不推薦用源碼,由於源碼編譯涉及相關參數)。
不過包管理器上的並不是是最新的,還多是很老舊的版本,因此須要咱們去官網下載編譯好的二進制來進行安裝.
關於安裝,我在個人其餘文章中有說到,比較簡單的.
在安裝的時候,會默認自帶一個 npm 包管理器,這個 npm 上託管了幾乎全部的 node.js 程序包,你可以經過它下載各類流行的基於 node.js 的軟件.html
固然,快速入門少不了 Hello World,Node.js其實和瀏覽器上的 javascript 差不太多,只是Node.js上增長了一些引用的方法以及結構,而且去除了 Dom 的操做(Node上並無Dom能夠操做..),因此,你能夠直接用如下語句打印出一句"Hello World":java
console.log("Hello World");
Node.js是一個服務器程序,固然就要提供Web服務,如下代碼能讓你創建起一個最基礎的Web服務器,由於它對全部的請求都只返回一樣的頁面:node
//app.js var http = require('http'); http.createServer(function(req, res) { res.writeHead(200, {'Content-Type': 'text/html'}); res.write('<h1>Node.js</h1>'); res.end('<p>Hello World</p>'); }).listen(3000); console.log("HTTP server is listening at port 3000.");
在js 中,最重要的部分之一就是它的異步編程,經過事件輪詢,在單線程上它可以接受更多的請求而且將資源最大化利用.
好比像下面的讀取文件程序,在調用讀取函數後,程序會繼續往下運行,等到讀取完成後,纔會調用讀取函數所綁定的那個回調函數:git
//readfilesync.js var fs = require('fs'); var data = fs.readFileSync('file.txt', 'utf-8'); console.log(data); console.log('end.');
node的幾乎全部程序都是經過各類模塊以及包組合完成的.每一個模塊或者包都有他特殊的功能以及特定的調用方法.
建立及加載模塊:github
// 讓咱們以一個例子來了解模塊。建立一個 module.js 的文件,內容是: //module.js var name; exports.setName = function(thyName) { name = thyName; }; exports.sayHello = function() { console.log('Hello ' + name); }; // 在同一目錄下建立 getmodule.js,內容是: //getmodule.js var myModule = require('./module'); myModule.setName('BYVoid'); myModule.sayHello();
在同一個程序中,同一個模塊只會被加載一次,node會經過將模塊的地址進行 hash並存起來,因此不會加載屢次.固然這樣的話,你在程序中引用兩次同一個模塊,他們實際上是一個.web
模塊經過 exports 暴露相關的方法或者屬性,未經過此方法暴露的方法和屬性是沒法被外界訪問到的(和java C++ C# 中的類差很少)
可是,你不能直接經過如下方式來覆蓋export函數,這樣的話不會有任何效果express
export = function(){ console.log("Hello"); }
當咱們只須要暴露一個方法或屬性的時候,用exports 就略顯複雜,我麼能夠經過如下方式將 exports 進行覆蓋:npm
module.exports = function(){ console.log("Hello"); }
每一個包中有不少的模塊,由於以前咱們知道,每一個模塊最好是單獨存放在一個js文件中,那包咱們就應該存放在一個文件夾中.而且提供一個外部訪問的接口(一般是一個模塊),用於總體管理及使用這個包的全部功能.
Node.js 在調用某個包時,會首先檢查包中 package.json 文件的 main 字段,將其做爲包的接口模塊,若是 package.json 或 main 字段不存在,會嘗試尋找 index.js 或 index.node 做
爲包的接口。
package.json 是 CommonJS 規定的用來描述包的文件,徹底符合規範的package.json 文件應該含有如下字段。
空格。
字段。
數組的第一個元素。
許可證文本的地址)字段。
url (倉庫的地址)和 path (相對於倉庫的路徑,可選)字段。
下面是一個徹底符合 CommonJS 規範的 package.json 示例:
{ "name": "mypackage", "description": "Sample package for CommonJS. This package demonstrates the required elements of a CommonJS package.", "version": "0.7.0", "keywords": [ "package", "example" ], "maintainers": [ { "name": "Bill Smith", "email": "bills@example.com", } ], "contributors": [ { "name": "BYVoid", "web": "http://www.byvoid.com/" } ], "bugs": { "mail": "dev@example.com", "web": "http://www.example.com/bugs" }, "licenses": [ { "type": "GPLv2", "url": "http://www.example.org/licenses/gpl.html" } ], "repositories": [ { "type": "git", "url": "http://github.com/BYVoid/mypackage.git" } ], "dependencies": { "webkit": "1.2", "ssl": { "gnutls": ["1.0", "2.0"], "openssl": "0.9.8" } } }
經過使用Node.js的包管理器,你能夠下載到幾乎全部的js包.
獲取一個包以下
npm install express
以上代碼將會將express安裝到當前項目的文件中
若是要將其安裝在全局(當前電腦一次安裝,全部地方均可以使用),能夠在參數中加入 -g
,若是是要將其加入項目依賴,能夠加入如下參數 --save-dev
,這樣node會自動將當前包的信息寫入到項目的 package.json 中.
這個略過,並不打算髮布,等須要時看也不遲
調試其實方法不少,能夠直接在命令行中進行單步調試,如下是nodejs支持的調試命令:
命令 | 功能 |
---|---|
run | 執行腳本,在第一行暫停 |
restart | 從新執行腳本 |
cont, c | 繼續執行,直到遇到下一個斷點 |
next, n | 單步執行 |
step, s | 單步執行並進入函數 |
out, o | 從函數中步出 |
setBreakpoint(), sb() | 在當前行設置斷點 |
setBreakpoint(‘f()’), sb(...) | 在函數f的第一行設置斷點 |
setBreakpoint(‘script.js’, 20), sb(...) | 在 script.js 的第20行設置斷點 |
clearBreakpoint, cb(...) | 清除全部斷點 |
backtrace, bt | 顯示當前的調用棧 |
list(5) | 顯示當前執行到的先後5行代碼 |
watch(expr) | 把表達式 expr 加入監視列表 |
unwatch(expr) | 把表達式 expr 從監視列表移除 |
watchers | 顯示監視列表中全部的表達式和值 |
repl | 在當前上下文打開即時求值環境 |
kill | 終止當前執行的腳本 |
scripts | 顯示當前已加載的全部腳本 |
version | 顯示 V8 的版本 |
這個程序很是好用,雖然我沒有用過,可是看上去很像谷歌瀏覽器的調試,之後須要時能夠試試看.
在Node中,有一個相似在瀏覽器中的window同樣的全局對象,叫作 global. console,process等都是其子.
如何定義全局對象就很簡單了:直接綁定在global上的,定義在最外層的,還有沒有使用var聲明的都是全局對象.
這個對象存儲了與當前運行環境相關的不少信息,而且也是標準輸入輸出的最底層接口,咱們在調用console.log()時,其背後也是經過process來實現的.
其含有如下幾個對象
下次事件循環調響應時調用 callback。這個能夠用在將兩個大型的耗時操做進行拆散.
這個對象是和咱們打交道最多的對象,其含有如下方法:
這個方法提供了一個方便的途徑讓咱們進行繼承操做,用法以下
util.inherits(constructor, superConstructor)
將兩個對象進行繼承操做
注意,此處繼承只會繼承原型中定義的屬性和方法!!而且 console.log() 並不會打印出原型中的屬性或者方法.
util.inspect(object,[showHidden],[depth],[colors]) 是一個將任一對象轉換爲字符串的方法.它不會調用對象的 toString 方法.
除了以上咱們介紹的幾個函數以外, util還提供了util.isArray()、 util.isRegExp()、
util.isDate()、util.isError() 四個類型測試工具,以及 util.format()、util.debug() 等工具。
events 是 node最重要的模塊.由於node整個運行就是基於事件輪詢的.
events只提供了一個對象: events.EventEmitter.這個對象的核心就是封裝事件功能.下面的代碼向咱們演示了這個過程:
var events = require('events'); var emitter = new events.EventEmitter(); emitter.on('someEvent', function(arg1, arg2) { console.log('listener1', arg1, arg2); }); emitter.on('someEvent', function(arg1, arg2) { console.log('listener2', arg1, arg2); }); emitter.emit('someEvent', 'byvoid', 1991);
這就是EventEmitter最簡單的用法。接下來咱們介紹一下EventEmitter經常使用的API。
符串 event 和一個回調函數 listener。
遞若干可選參數到事件監聽器的參數表。
監聽器最多隻會觸發一次,觸發後馬上解除該監聽器。
器,listener 必須是該事件已經註冊過的監聽器。
若是指定 event,則移除指定事件的全部監聽器。
EventEmitter定義了一個特殊的叫 error 的事件.當error被觸發時,若是沒有定義的響應監聽器,則會退出程序並打印調用棧.
因此咱們要發射 error 時,必需要爲其設置相應的監聽器,來捕獲並處理錯誤,這樣纔不會致使程序掛掉.
通常狀況下,咱們不會直接用到這個對象,而是在繼承中使用它.包括fs,http等都是這樣的操做.
爲何要這樣作呢?緣由有兩點。首先,具備某個實體功能的對象實現事件符合語義,
事件的監聽和發射應該是一個對象的方法。其次 JavaScript 的對象機制是基於原型的,支持部分多重繼承,繼承 EventEmitter 不會打亂對象原有的繼承關係。
fs 模塊是文件操做的封裝,它提供了文件的讀取、寫入、改名、刪除、遍歷目錄、連接等 POSIX 文件系統操做。與其餘模塊不一樣的是,fs 模塊中全部的操做都提供了異步的和同步的兩個版本,例如讀取文件內容的函數有異步的 fs.readFile() 和同步的 fs.readFileSync()。咱們以幾個函數爲表明,介紹 fs 經常使用的功能,並列出 fs 全部函數的定義和功能。
這個函數可以讀取文件中的內容,其用法爲:
fs.readFile(filename,[encoding],[callback(err,data)])
如下是調用示例:
var fs = require('fs'); fs.readFile('content.txt', 'utf-8', function(err, data) { if (err) { console.error(err); } else { console.log(data); } });
fs.readFileSync(filename, [encoding])是 fs.readFile 同步的版本。它接受的參數和 fs.readFile 相同,而讀取到的文件內容會以函數返回值的形式返回。若是有錯誤發生,fs 將會拋出異常,你須要使用 try 和 catch 捕捉並處理異常。
fs.open(path, flags, [mode], [callback(err, fd)])是 POSIX open 函數的封裝,與 C 語言標準庫中的 fopen 函數相似。它接受兩個必選參數,path 爲文件的路徑,flags 能夠是如下值:
mode 參數用於建立文件時給文件指定權限,默認是 0666。回調函數將會傳遞一個文
件描述符 fd。
fs.read(fd, buffer, offset, length, position, [callback(err, bytesRead, buffer)])是 POSIX read 函數的封裝,相比 fs.readFile 提供了更底層的接口。
如下是其示例:
var fs = require('fs'); fs.open('content.txt', 'r', function(err, fd) { if (err) { console.error(err); return; } var buf = new Buffer(8); fs.read(fd, buf, 0, 8, null, function(err, bytesRead, buffer) { if (err) { console.error(err); return; } console.log('bytesRead: ' + bytesRead); console.log(buffer); }) });
固然,fs中的函數是不少的,若是須要,能夠去網上進行更詳細的查閱.
其實在node中就已經封裝了一個很底層的http模塊,http.Server,幾乎全部的網絡工做都能經過它來完成.
如下代碼
//app.js var http = require('http'); http.createServer(function(req, res) { res.writeHead(200, {'Content-Type': 'text/html'}); res.write('<h1>Node.js</h1>'); res.end('<p>Hello World</p>'); }).listen(3000); console.log("HTTP server is listening at port 3000.");
會創建一個在3000端口監聽的程序
//httpserverrequestget.js var http = require('http'); var url = require('url'); var util = require('util'); http.createServer(function(req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end(util.inspect(url.parse(req.url, true))); }).listen(3000);
//httpserverrequestpost.js var http = require('http'); var querystring = require('querystring'); var util = require('util'); http.createServer(function(req, res) { var post = ''; req.on('data', function(chunk) { post += chunk; }); req.on('end', function() { post = querystring.parse(post); res.end(util.inspect(post)); }); }).listen(3000);
服務器不只要接收數據,也要返回相應的數據給客戶端:
http.ServerResponse 是返回給客戶端的信息,決定了用戶最終能看到的結果。它
也是由 http.Server 的 request 事件發送的,做爲第二個參數傳遞,通常簡稱爲
response 或 res。
http.ServerResponse 有三個重要的成員函數,用於返回響應頭、響應內容以及結束
請求。
encoding 來講明它的編碼方式,默認是 utf-8。在 response.end 調用以前,
response.write 能夠被屢次調用。
成。當全部要返回的內容發送完畢的時候,該函數 必須 被調用一次。它接受兩個可
選參數,意義和 response.write 相同。若是不調用該函數,客戶端將永遠處於等待狀態。
固然,node還能充當一個http的客戶端程序來使用 http 模塊提供了兩個函數 http.request 和 http.get,功能是做爲客戶端向 HTTP服務器發起請求。
http.request(options, callback) 發起 HTTP 請求。接受兩個參數, option 是一個相似關聯數組的對象,表示請求的參數, callback是請求的回調函數。 option經常使用的參數以下所示。
callback 傳遞一個參數,爲 http.ClientResponse 的實例。
http.request 返回一個 http.ClientRequest 的實例。
下面是一個經過 http.request 發送 POST 請求的代碼:
//httprequest.js var http = require('http'); var querystring = require('querystring'); var contents = querystring.stringify({ name: 'byvoid', email: 'byvoid@byvoid.com', address: 'Zijing 2#, Tsinghua University', }); var options = { host: 'www.byvoid.com', path: '/application/node/post.php', method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Content-Length' : contents.length } }; var req = http.request(options, function(res) { res.setEncoding('utf8'); res.on('data', function (data) { console.log(data); }); }); req.write(contents); req.end();
http.get(options, callback) http 模塊還提供了一個更加簡便的方法用於處
理GET請求: http.get。它是 http.request 的簡化版,惟一的區別在於http.get
自動將請求方法設爲了 GET 請求,同時不須要手動調用 req.end()。
//httpget.js var http = require('http'); http.get({host: 'www.byvoid.com'}, function(res) { res.setEncoding('utf8'); res.on('data', function (data) { console.log(data); }); });
post 和 get 返回的數據皆爲 http.ClientRequest 對象.其也提供了write和end函數,使用以下:
//httpresponse.js var http = require('http'); var req = http.get({host: 'www.byvoid.com'}); req.on('response', function(res) { res.setEncoding('utf8'); res.on('data', function (data) { console.log(data); }); });
其還提供瞭如下函數:
此外還有 request.setNoDelay([noDelay])、request.setSocketKeepAlive
([enable], [initialDelay]) 等函數。
同時也有 http.ClientResponse,其與 http:ServerResponse類似,提供... data,end和close,分別在數據到達,傳輸結束和連接結束時觸發,其中 data 事件傳遞一個參數 chunk,表示接收到的數據.
http.ClientResponse 還提供瞭如下幾個特殊的函數。
時,數據將會以 encoding 編碼。默認值是 null,即不編碼,以 Buffer 的形式存
儲。經常使用編碼爲 utf8。
安裝npm install -g express
express -t ejs XXXX
接下來的 Nodejs 博客搭建暫未記錄,由於涉及到的知識點較多,須要的話最好仍是從新讀一次.
在node中,共有兩種類型的模塊:核心模塊,文件模塊.核心模塊是由node自帶的一些基礎模塊,具備最高的加載優先級,文件模塊則是咱們本身建立的或者引用的三方模塊.
若是指定了加載路徑,則有如下兩種查找狀況
當咱們沒有指定路徑時,node會在node_moudule目錄中去查找,有趣的是,在這裏有一個很大的性能問題:
好比你在/home/aiello/develop/foot.js
中使用require("bar.js")
,node會在當前目錄的node_modules文件夾中尋找該模塊,若是未找到,則會從新往上一級查找,因而node到/home/aiello/develop
這級目錄進行查找,若是尚未它會繼續往上進行查找,知道找到根目錄,發現沒有,因而報錯.
能明顯看出來,node在模塊的查找中很是的費時,因此咱們應當將模塊放到距離當前應用最近的目錄,而且最好是指定模塊路徑.
在循環中使用異步方法,將會遇到
//forloop.js var fs = require('fs'); var files = ['a.txt', 'b.txt', 'c.txt']; for (var i = 0; i < files.length; i++) { fs.readFile(files[i], 'utf-8', function(err, contents) { console.log(files[i] + ': ' + contents); }); }
這是因爲回調函數太慢了,早都循環完了,纔會調用到回調函數,因此最後回調函數中的i都是等於循環結束時的i(不必定),因此會有相關問題,如下代碼將其作一個閉包封裝,以達到理想效果:
//forloopclosure.js var fs = require('fs'); var files = ['a.txt', 'b.txt', 'c.txt']; for (var i = 0; i < files.length; i++) { (function(i) { fs.readFile(files[i], 'utf-8', function(err, contents) { console.log(files[i] + ': ' + contents); }); })(i); }
普通 Node.js 應用存在如下問題:
這個簡單,不作概述
使用cluster模塊,能夠實現多進程以及主進程與工做進程的結構.
製做一個啓動腳本便可
虛擬主機便可
so,這個我知道,他不適合作
起始位置
PDF 154
頁碼 148
起始位置:PDF 173頁碼 168