nodejs學習筆記

來源:互聯網
上載者:User

標籤:命令列   也有   ecif   mpi   syn   common   esc   表示   移除   

Hello Fuck如下:

console.log(‘Hello, Fuck you, NodeJs‘);# node Helloworld.jsHello, Fuck you, NodeJs

事件:

Node.js所有的非同步i/o操作在完成時都會發送一個事件到事件隊列,事件由EventEmitter對象來提供,前面提到的fs.readFile和http.createServer的回呼函數都是通過EventEmitter來實現的。

//event.jsvar EventEmitter = require(‘events‘).EventEmitter;var event = new EventEmitter();event.on(‘some_event‘, function() {    console.log(‘some_event occurred.‘);    setTimeout(function(){        event.emit(‘some_event‘);    },1000);});setTimeout(function() {    event.emit(‘some_event‘);},1000);console.log(‘end?‘);# node event.js end?some_event occurred.some_event occurred.some_event occurred.^C

 nodejs不停監測是否有活動的事件監聽器比如i/o, timer等,一旦發現沒有活動的事件監聽器,nodejs進程將退出。

 

模組

模組是Node.js的基本組成部分,檔案和模組是一一對應的,換言之,一個Node.js檔案就是一個模組,這個檔案可能是JavaScript代碼,JSON或者編譯過的c/c++擴充。

前面章節的例子中,我們曾經用到了類似於var http=require(‘http‘),其中http就是一個核心模組,其內部是用c++來實現的,外部使用javascript來進行封裝。通過require函數擷取了這個模組之後,然後才能使用其中的對象。

建立,載入模組

在Node.js中,建立一個模組非常單簡單,因為一個檔案就是一個模組,我們關注的問題僅僅在於如何在其它檔案中擷取這個模組,Node.js提供了exports和require兩個對象,其中exports是模組公開的介面,而require用於從外部擷取一個模組的介面,也就是擷取返回的exports對象。

// module.jsvar name;exports.setName=function(theName) {    name=theName;}exports.sayHello=function() {    console.log(‘Fuck you ‘ + name);}// getModule.jsvar myModule=require(‘./module‘) //注意這裡需要./首碼,因為是相對當前工作目錄的。myModule.setName(‘Mosmith‘);myModule.sayHello();# node getModule.jsHello Mosmith

 

單次載入,這個有點類似於建立一個對象,但實際上和對象又有本質的區別,因為require不會重複載入模組,也就是說無論調用多少次require,獲得的模組都是同一個。

覆蓋exports,有時候我們只是想將一個對象封閉到一個模組中,例如:

// module.jsfunction Hello() {    var name;    this.setName=function(_name) {        this.name=_name;    }    this.sayHello=function() {        console.log("Hello " + this.name);    }}exports.Hello=Hello;// override exports object//module.exports=Hello;


// getModule.js
var Hello = require(‘./module.js‘).Hello;
var hello=new Hello();
hello.setName(‘Mosmith‘);
hello.sayHello();

需要注意的是,不可以通過對 exports 直接賦值代替對 module.exports 賦值。exports 實際上只是一個和 module.exports 指向同一個對象的變數,它本身會在模組執行結束後釋放,但 module 不會,因此只能通過指定module.exports 來改變提供者。

 

包是在模組的基礎上更深一步的抽像,Node.js的包類似於c/c++的函數庫或者Java/.Net的類庫,它將某個獨立的功能封裝起來,用於發布,更新,依賴管理和版本控制,Node.js根據CommonJS規範實現了包機制,開發了npm來解決包的發布和擷取需求。

Node.js的包是一個目錄,其中包含了一個JSON格式的說明檔案,package.json,嚴格符合CommonJS的包應該具備以下特徵。

  1. package.json必須在包的頂層目錄下
  2. 二進位檔案應該在bin目錄下
  3. JavaScript代碼應該在lib目錄下
  4. 文檔應該在doc目錄下
  5. 單元測試應該在test目錄下

但Node.js對包的要求沒有這麼嚴格,只要頂層目錄下面有package.json,並符合一些規範即可。但最好是符合規範。Node.js在調用某個包是,先會去檢查包中的package.json中的main欄位,將其作為包的介面模組,如果package.json或者main欄位不存在,那麼會嘗試將尋找index.js或者index.node作為包的介面。

package.json是CommonJS規定用於描述包的檔案,完整的包應該含有以下欄位:

name:包的名稱,必須是唯一的由小寫字母,數字,和底線組成,不能有空格。

description:包的簡要說明。

version:符合語義化版本識別規範的字串

maintainer:維護者數組,第個元素要包含name, email(可選), web(可選)

contributors:貢獻者數組,格式與maintainer相同,包的作者應該是都數組的第一個元素。

bugs提交bug的地址。

licenses許可證數組,每個元素要包含type的url

repositories倉庫託管地址數組,每個元素要包含type(倉庫的類型比如git),url(倉庫的地址)和path(相對於倉庫的路徑,可選)欄位。

dependencies:包的依賴,一個關聯陣列,由包的名稱和版本號碼組成。

下面是一下符合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": "[email protected]",    }],"contributors": [    {        "name": "BYVoid",        "web": "http://www.byvoid.com/"    }],"bugs": {    "mail": "[email protected]",    "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"        }}}

 

npm是Node.js的包管理工具,它已經成為Node.js包的標準發布平台。用於Node.js包的發布,傳播,依賴控制。

npm install/i package_name比如要安裝express

npm install express或者npm i express

同時npm還會自動解析其依賴,並擷取express依賴的mime,mkdirp,qs的connect等。

 

本地模組與全域模式

預設情況下npm會從http://npmjs.org搜尋並下載包,並將包安裝到當前目前的node_modules子目錄下面。也就是本地模式。

另外npm可以以全域模式安裝(使用-g參數),使用方法為:

npm install/i -g packageName

但需要注意的是,全域模式下可能會造成衝突,因為別的nodejs程式可能需要另外版本的包。

 

本地模式下npm不會註冊環境變數,而全域模式下會注意環境變數,並將包安裝到系統目錄比如/usr/local/lib/node_modules,同時package.json檔案中的bin欄位包含的檔案會被連結到/usr/local/bin。/usr/local/bin是在PATH環境變數中預設定義的,因此就可以直接在命令中運行像supervisor的模組了。但全域模式安裝的package不能通過require來使用,因為require不會去搜尋/usr/local/lib/node_modules目錄。

 

建立全域連結

npm提供了一個npm link命令,它的功能是在當地套件和全域包之間建立符號連結,我們說過使用全域模式安裝的包不能通過require來使用,但通過npm link命令可以繞過這個限制。比如:

npm link express

這裡可以在node_modules子目錄發現一個安裝到全域的包的符號連結。但這個命令不能在windows下來使用。

 

調試。

node debug debug.js

node --debug[=port] script.js 然後在另一個終端node debug localhost:debug_port或者使用IDE來進行遠端偵錯。

 

全域對象

JavaScript中有一個特殊的對象,稱為全域對象,它所有的屬性可以在程式的任何地方訪問,也就是說全域變數,在瀏覽器的JavaScript中,通常window是全域對象,而Node.js中的全域對象是global,所有的全域變數(除了global本身以外),都是global對象的屬性。我們在Node.js中能夠直接存取到對象通過都是global的屬性比如console, process等。

 

全域對象與全域變數

global最根本的作用是作為全域變數的宿主,按照ECMAScript的定義,滿足以下條件的是全域變數。

  1. 最外層定義的變數。
  2. 全域對象的屬性。
  3. 隱式定義的變數(未定義直接同賦值的變數)

當你定義一個全域變數時,這個變數同時也會成為全域對象的屬性,反之亦然。需要注意的是,在 Node.js 中你不可能在最外層定義變數,因為所有使用者代碼都是屬於當前模組的,而模組本身不是最外層上下文,提倡永遠使用 var 定義變數以避免引入全域變數,因為全域變數會汙染命名空間,提高代碼的耦合風險。

 

process

process是一個全域變數,即global對象的一個屬性,它用於描述當前Node.js進程的狀態,提供了一個與作業系統的簡單介面。寫一些本地命令列的程式的時候經常需要和它打交道的。

process.argv是命令列參數數組,第一個元素是node,第二個元素是指令檔名,從第三個元素開始每個元素是一個運行參數。

process.stdout是標準輸出資料流,通常我們使用的console.log向標準輸出列印字元,而process.stdout.write()函數則提供更加底層的介面。

process.stdin是標準輸入資料流,初始時它是被暫停,想要從標準輸入讀取資料你必須恢複流,並手動編寫流的事件響應函數。比如下面:

 

process.nextTick(callback)的功能是為事件迴圈設定一項任務,Node.js會在下一次事件迴圈時調用callback。Node.js 適合 I/O 密集型的應用,而不是計算密集型的應用,因為一個 Node.js 進程只有一個線程,因此在任何時刻都只有一個事件在執行。如果這個事件佔用大量的 CPU 時間,執行事件迴圈中的下一個事件就需要等待很久,因此 Node.js 的一個編程原則就是盡量縮短每個事件的執行時間。 process.nextTick() 提供了一個這樣的工具,可以把複雜的工作拆散,變成一個個較小的事件。

process.stdin.on(‘data‘, function(data) {    process.nextTick(function() {        process.stdout.write(‘do something very time-consuming‘);        process.stdout.write(data);    });});

需要setTimeout也可以達到類似的作用,但setTimeout效率很低,回調不能被及時執行。

除了上面幾個比較常用的成員,除些之後有process.platform,process.pid,process.execPath,process.memoryUsage(),以及POSIX進程訊號響應機制。

 

console

console用於提供控制台標準/錯誤輸出:

console.log()向標準輸出資料流列印字元並以分行符號結束。console.log接受若干個參數,如果只有一個參數,則輸出這個參數的字串形式,如果有多個參數,則類似於c語言的printf命令的格式化輸出。

console.log("Helloworld"); => Helloworld
console.log("Helloworld%s"); => Helloworld%sconsole.log("Helloworld %s", Mosmith); => Helloworld Mosmith

console.error()與console.log相同,只不過console.error()向標準錯誤流輸出。

console.trace()用於向標準錯誤流輸出當前的調用棧。

 

常用工具util

util是Node.js的核心模組,提供常用函數的集合,用於彌補核心JavaScript的功能過於精簡的不足。

util.inherits(constructor, superConstructor)是一個實現對象間原型繼承的函數,JavaScript的物件導向我是基於原型的,與常見的基於類不同,JavaScript並沒有提供對象繼承的語言層級特性,而是通過原型複製來實現的,具體細節我們在附錄A中說明,這裡我們只介紹util.inerits的用法,樣本如下:

var util=require(‘util‘)function Base() {  this.name=‘base‘;    this.base=1991;    this.sayHello = function() {        console.log(‘Hello ‘ + this.name);    }}Base.prototype.showName=function() {    console.log(this.name);}function Sub() {    this.name=‘sub‘;}util.inherits(Sub,Base);var objBase=new Base();objBase.showName();objBase.sayHello();console.log(objBase);var objSub=new Sub();objSub.showName();// This is undefined in Sub// objSub.sayHello();console.log(objSub);

 

util.inspect

util.inspect(object, [showHidden],[depth],[colors])是一個將任意對象轉換為字串的方法,通常用於調試和錯誤輸出,它至少一個參數object,即要轉換的對象,showHidden是一個可選的參數,如果值為true,將會輸出更多的參數,depth表示最大的遞迴層數,如果對象很複雜,你可以指定層數以控制輸出資訊的多少,預設情況下遞迴兩層,為null的情況下則不限層數。

 

事件驅動events

events是Node.js的最重要的模組,Node.js本身就是依賴於event實現事件驅動的,而它提供了唯一的介面。events模組不僅僅用於使用者代碼與Node.js下層事件迴圈的互動,還幾乎被所有的模組依賴。

 

事件發射器

events模組只提供了一個對象,events.EventEmitter, EventEmitter的核心就是事件發射與事件監聽器功能的封裝。EventEmitter的每一個事件由一個事件和若干個參數組成,事件名是一個字串,通常表達一定的語義,對於每個事件,EventEmitter支援若干個事件監聽器,當事件發射時,註冊到這個事件的事件監聽器將被依次調用,事件參數作為回呼函數傳遞。

// eventEmitterTest.js
var events=require(‘events‘);var emitter=new events.EventEmitter();emitter.on(‘someEvent‘,function(arg1,arg2){ console.log(‘listener1 invoked‘,arg1,arg2);});emitter.on(‘someEvent‘, function(arg1,arg2) { console.log(‘listener2 invoked‘,arg1,arg2);});emitter.emit(‘someEvent‘,‘argument1‘,2017);$ node eventEmitterTest.js listener1 invoked argument1 2017listener2 invoked argument1 2017
  • EventEmitter.on(event, listener) 為指定事件註冊一個監聽器,接受一個字串 event 和一個回呼函數 listener 。
  • EventEmitter.emit(event, [arg1], [arg2], [...]) 發射event事件,傳遞若干選擇性參數到事件監聽器的參數表。
  • EventEmitter.once(event, listener) 為指定事件註冊一個單次監聽器,即監聽器最多隻會觸發一次,觸發後立刻解除該監聽器。
  • EventEmitter.removeListener(event, listener) 移除指定事件的某個監聽器, listener 必須是該事件已經註冊過的監聽器。
  • EventEmitter.removeAllListeners([event]) 移除所有事件的所有監聽器,如果指定 event ,則移除指定事件的所有監聽器

error事件

EventEmitter定義了一個特殊的事件error,它包含了’錯誤‘的語義,我們在遇到異常的時候通常會發射error事件。當error被發射時,EventEmitter規定如果沒有響應的監聽器,那麼Node.js會將它當作異常,退出程式並列印調用棧。因此我們一般要為會發射error事件的對象設定監聽器,避免遇到錯誤後整個程式崩潰。比如:

var events = require(‘events‘);var emitter = new events.EventEmitter();emitter.emit(‘error‘);運行時會顯示以下錯誤:node.js:201throw e; // process.nextTick error, or ‘error‘ event on first tick^Error: Uncaught, unspecified ‘error‘ event.at EventEmitter.emit (events.js:50:15)at Object.<anonymous> (/home/byvoid/error.js:5:9)at Module._compile (module.js:441:26)at Object..js (module.js:459:10)at Module.load (module.js:348:31)at Function._load (module.js:308:12)at Array.0 (module.js:479:10)at EventEmitter._tickCallback (node.js:192:40)

 

繼承EventEmitter

大多數時候我們不會直接使用 EventEmitter ,而是在對象中繼承它。包括 fs 、 net 、http 在內的,只要是支援事件響應的核心模組都是 EventEmitter 的子類。為什麼要這樣做呢?原因有兩點。首先,具有某個實體功能的對象實現事件符合語義,事件的監聽和發射應該是一個對象的方法。其次 JavaScript 的對象機制是基於原型的,支援部分多重繼承,繼承 EventEmitter 不會打亂對象原有的繼承關係。

 

檔案系統fs

fs模組是檔案操作的封閉,它提供了檔案的讀取,寫入,更名,刪除,遍曆目錄,連結等POSIX檔案操作,與其它模組不同的是,fs模組所有的操作都有同步和非同步兩個版本,例如讀取檔案內容的函數有非同步fs.readFile()也有同步的fs.readFileSync

fs.readFile(filename, [encoding], [callback(err,data)])是最簡單的讀取檔案的函數,它接受一個必選的參數filename,如果不提供encoding,那麼將以二進位方式開啟,如果指定了encoding,data是一個解析後的字串。

fs.readFIleSync是同步版本,它沒有callback參數,data通過傳回值擷取,而錯誤則需要通過try catch來進行捕捉處理。

fs.open(path, flag, [mode], [callback(err,fd])]是POSIX open函數的封裝,與c和fopen類似,它兩個必選參數,path為檔案路徑,flag是表示以什麼方式開啟檔案,mode參數用於建立檔案時給檔案指定許可權,預設是0666,回呼函數將傳遞一個錯誤參數,以及一個檔案描述符fd

fs.read(fd,buffer, offset, length, position, callback(err, byteRead, buffer)]是POSIX read函數的封閉,相比於fs.readFile, 它提供了更加底層的介面,fs.read功能是從指定的檔案描述符fd中讀取資料並寫入buffer指定的緩衝區對象,offset是buffer的寫入位移量,length是要從檔案中讀取的位元組數,position是檔案讀取的起始位置,如果position的值為null,則會從當前檔案指標的位置讀取,回呼函數傳遞byteRead和buffer,分別表示讀取的位元組數和緩衝區對象。

 

http模組

Node.js標準庫裡面提供了http模組,其中Node.js 標準庫提供了 http 模組,其中封裝了一個高效的 HTTP 伺服器和一個簡易的HTTP 用戶端。 http.Server 是一個基於事件的 HTTP 伺服器,它的核心由 Node.js 下層 C++部分實現,而介面由 JavaScript 封裝,兼顧了高效能與簡易性。 http.request 則是一個HTTP 用戶端工具,用於向 HTTP 伺服器發起請求,例如實現 Pingback 1 或者內容抓取

 

http.Server

http.Server是http模組中的HTTP伺服器對象,用Node.js做的所有基於HTTP協議的系統如網站,社交應用,甚於Proxy 伺服器,都是基於http.Server來實現的,它提供了一套封裝層級很低的API,僅僅是流量控制和簡單的訊息解析,所有的高層功能都要通過它的介面來實現。

 

nodejs學習筆記

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.