1. 程式人生 > >nodejs的基礎概念

nodejs的基礎概念

length lan 用戶輸入 相關配置 mov 目前 all 隊列 回調

1.node 安裝與相關配置。


2.Node.jsREPL(交互式解釋器)

類似於控制臺,可以輸入命令,並接受系統的響應。

REPL 的功能:

  1.讀取:讀取用戶輸入,解析輸入的 js 數據結構,並存儲在內存中。

  2.執行:執行輸入的數據結構。

  3.打印:輸出結果。

  4.循環:可以循環1、2、3操作指導ctrl+c兩次退出。

開啟 Node 終端:node 即可開啟。

運算符:+、-、*、/,還支持括號改變優先級。

變量定義:使用var來定義變量。常用的輸出 API:console.log()。

多行表達式:這裏指的是循環,與在 js 中做的循環是一致的。每輸出一行回車就可以,node 會自動檢測是否為連續多行表達式。

下劃線_變量:可以使用下劃線變量來獲取上一個表達式的運算結果。

REPL 命令:

  Ctrl+c 退出當前終端。

  Ctrl+c 連續兩次,退出Node REPL

  Ctrl+d 退出 Node REPL

  向上/向下鍵-查看輸入的歷史命令。

  tab 鍵 列出當前命令

  .help 列出使用命令

  .break 退出多行表達式

  .clear 退出多行表達式

  .save filename 保存當前的 Node REPL 會話到指定文件。

  .load filename 載入當前 Node REPL 會話的文件內容。


3. Node.js 回調函數

Node.js異步編程的直接體現就是回調。

異步編程依托於回調來實現,但是不能說使用回調就是異步化。

回調函數在完成任務後就會調用,Node使用了大量的回調函數,Node所有的API都支持回調函數。

註:阻塞是按順序執行的,而非阻塞是不需要按順序的,所以如果需要處理回調函數的參數,我們需要寫在回調函數內。


4.Node.js事件循環

Node.js是單進程單線程應用,但是通過事件和回調支持並發, 所以性能很高。

Node.js的每一個API都是異步的(這裏個人認為表達的意思應該是每一個API都是支持回調。參考第三部分),並作為一個獨立線程運行,使用異步函數調用,並處理並發。

Node.js基本上所有的事件機制都是用設計模式中的觀察者模式實現的。

Node.js單線程類似進入一個while(true)的事件循環,直到沒有事件,觀察者退出,每個異步事件都生成一個事件觀察者。如果有事件發生就調用該回調函數。

技術分享圖片

Node.js中內置多個事件,可以引入events模塊,並通過實例化EventEmitter類來綁定和監聽事件。

技術分享圖片

在Node中:執行異步操作的函數將回調函數作為最後一個參數,回調函數接受錯誤對象作為第一個參數。

技術分享圖片


5.Node.js EventEmitter

Node.js 所有的異步I/O操作在完成時都會發送一個事件到事件隊列。

Node.js裏面的許多對象都會分發事件:一個net.Server對象會在每次有新連接時分發一個事件,一個fs.readStream對象會在文件被打開的時候發出一個事件。所有產生的事件的對象都是events.EventEmitter的實例。

EventEmitter類

events模塊只提供了一個對象,events.EventEmitter。EventEmitter的核心就是事件觸發與事件監聽器功能的封裝。

// 引入 events 模塊
var events = require(‘events‘);
// 創建 eventEmitter 對象
var eventEmitter = new events.EventEmitter();

EventEmitter對象如果再實例化時發生錯誤,就會觸發error事件。當添加新的監聽器時,newListener事件會觸發,當監聽器被移除時,removeListener事件被觸發。

簡例說明EventEmitter用法:

//event.js文件
var EventEmitter = require(‘events‘).EventEmitter;
var event = new EventEmitter();
event.on(‘some_evnet‘, function() {
    console.log(‘some_event 事件觸發‘);    
});
setTimeOut(function() {
    event.emit(‘some_event‘);
}, 1000);

技術分享圖片

EventEmitter的每個事件由一個事件名和若幹個參數組成,事件名是一個字符串,通常表達一定的含義,對於每個事件EventEmitter支持若幹個事件監聽器。

當事件觸發時,註冊到這個事件的監聽器被依次調用,事件參數作為回調函數參數傳遞。

簡例代碼:

//event.js文件
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‘, ‘arg1參數‘, ‘arg2參數‘);

執行結果:

技術分享圖片

在上述例子中,emitter為事件註冊了兩個監聽器,然後觸發了事件。這是最簡單的EventEmitter的用法。

EventEmitter提供了多個屬性,如on用於事件綁定,emit用於觸發一個事件。

具體的API

error事件

EventEmitter定義了一個特殊的事件error,它包含了錯誤的語義,我們在遇到異常時,通常會觸發error事件。

當error被觸發時,EventEmitter規定如果沒有響應的監聽器,Node.js會把它當做異常,退出程序並輸出錯誤信息。

我們一般要為會觸發error事件的對象設置監聽器,避免出現錯誤後整個程序崩潰。

技術分享圖片

關於EventEmitter,

我們大多時候只會在對象中繼承它,包括fs、net、http在內的。只要是支持事件響應的核心模塊都是EventEmitter的子類。原因有二:

1.具有某個實體功能的對象實現事件符合語義,事件的監聽和發生應該是一個對象的方法。

2.js的對象機制是基於原型的,支持部分多繼承,繼承EventEmitter不會打亂對象原有的繼承關系。

註:補充:實踐隊列中出現一個未綁定事件會觸發error事件,若未綁定error事件則程序拋出異常結束。


6.Node.js Buffer(緩沖區)

js只有字符串數據類型,沒有二進制數據類型。但是在處理流時,必須使用二進制數據,因此在Node.js中定義了Buffer類,該類用來創建一個專門存放二進制數據的緩存區。

Buffer與字符編碼

Buffer實例一般用於表示編碼字符的序列,比如UTF-8、UCS2、Base64、或者十六進制編碼的數據,通過使用顯式的字符編碼,就可以在Buffer實例與普通的JavaScript字符串之間進行相互轉換。

const buf = Buffer.from(‘runoob‘,‘ascii‘);
//輸出72756e6f6f62
console.log(buf.toString(‘hex‘));
//輸出cnVub29i
console.log(buf.toString(‘base64‘));

Node.js目前支持的字符編碼包括:

  ascII  僅支持7位ASCII數據。如果設置去掉高位的話,這種編碼是非常快。

  utf8  多字節編碼的Unicode字符,許多網頁和其他文檔格式都使用UTF-8。

  utf16le  2或4個字節,小字節編碼的Unicode字符。支持代理對(U+100000至U+10FFF)。

  usc2  utf16le的別名。

  base64  Base64編碼。

  latin1  一種把Buffer編碼成一字節編碼的字符串的方式。

  binary  Latin1的別名。

  hex  將兩個字節編碼為兩個十六進制字節。

創建Buffer類

Buffer提供了以下API創建Buffer類:

技術分享圖片

//創建一個長度為10、且用0填充的buffer
const buf1 = buffer.alloc(10);

//創建一個長度為10、且用0x1填充的buffer。
const buf2 = Buffer.alloc(10,1);

//創建一個長度為10、且未初始化的Buffer。
//這個方法比調用Buffer.alloc()更快。
//但返回的Buffer實例可能包含舊數據。
//因此需要使用fill()或write()重寫。
const buf3 = Buffer.allocUnsafe(10);

//創建一個包含[0x1, 0x2, 0x3]的Buffer
const buf4 = Buffer.from([1,2,3]);

//創建一個包含 UTF-8 字節 [0x74, 0xc3, 0xa9, 0x73, 0x74] 的 Buffer。
const buf5 = Buffer.from(‘tést‘);

// 創建一個包含 Latin-1 字節 [0x74, 0xe9, 0x73, 0x74] 的 Buffer。
const buf6 = Buffer.from(‘tést‘, ‘latin1‘);

寫入緩沖區

語法:

寫入Node緩沖區的語法如下所示:

buf.write(string[, offset[, length]][,encoding])

參數:

技術分享圖片

根據encoding的字符編碼寫入string到buf中的offset位置。length參數是寫入的字節數。如果buf沒有足夠的空間保存整個字符串,則只會寫入string的一部分,只部分解碼的字符不會被寫入。

返回值:

返回實際寫入的大小。如果buffer空間不足,則只會寫入部分字符串。

技術分享圖片

從緩存區讀取數據

語法讀取Node緩沖區數據的語法如下:

buf.toString([encoding[, start[,end]]])

技術分享圖片

buf = Buffer.alloc(26);
for(var i = 0; i < 26; i++) {
    buf[i] = i + 97;
}

console.log(buf.toString(‘ascii‘));        //輸出:abcdefghijklmnopqrstuvwxyz
console.log(buf.toString(‘ascii‘, 0, 5));    // 輸出: abcde
console.log(buf.toString(‘utf8‘, 0 ,5));    //輸出:abcde
console.log(buf.toString(undefined, 0, 5)); //使用 ‘utf8‘ 編碼, 並輸出: abcde

技術分享圖片

將Buffer轉換為JSON對象

語法:將Node Buffer轉換為JSON對象的函數語法格式:

buf.toJSON()

當字符串化為一個Buffer實例時,JSON.stringify()會隱式地調用該toJson();

技術分享圖片

const buf = Buffer.from([0x1, 0x2, 0x3, 0x4, 0x5]);
const json = JSON.stringify(buf);

// 輸出: {"type":"Buffer","data":[1,2,3,4,5]}
console.log(json);

const copy = JSON.parse(json, (key, value) => {
  return value && value.type === ‘Buffer‘ ?
    Buffer.from(value.data) :
    value;
});

// 輸出: <Buffer 01 02 03 04 05>
console.log(copy);

技術分享圖片

緩沖區合並

語法:

Buffer.concat(list[, totalLength])

技術分享圖片

var buffer1 = Buffer.from((‘菜鳥教程‘));
var buffer2 = Buffer.from((‘www.runoob.com‘));
var buffer3 = Buffer.concat([buffer1,buffer2]);
console.log("buffer3 內容: " + buffer3.toString());

技術分享圖片

緩沖區比較

語法:

buf.compare(otherBuffer);

技術分享圖片

var buffer1 = Buffer.from(‘ABC‘);
var buffer2 = Buffer.from(‘ABCD‘);
var result = buffer1.compare(buffer2);

if(result < 0) {
   console.log(buffer1 + " 在 " + buffer2 + "之前");
}else if(result == 0){
   console.log(buffer1 + " 與 " + buffer2 + "相同");
}else {
   console.log(buffer1 + " 在 " + buffer2 + "之後");
}
技術分享圖片

技術分享圖片

技術分享圖片

技術分享圖片

nodejs的基礎概念