process
是一個全局的變量,因此使用的時候是不須要執行require
操做,能夠直接使用。css
這裏分兩部分來講明,第一個就是能夠藉助它去獲取進程信息,好比進程工做的時候本地是一個什麼樣的環境,經過process
能夠獲取。第二個經過process
能夠對當前的進程作一些操做,好比說能夠監聽進程執行過程當中內置的事件,建立子進程完成更多的操做。html
// 查看內存消耗
console.log(process.memoryUsage());
/** * rss: 常駐內存 * heapToal: 總內存大小 * heapUsed: 已使用內存 * external: 擴展內存 - 底層模塊佔用的C/C++核心模塊 * arrayBuffers: 緩衝區大小 */
複製代碼
console.log(process.cpuUsage());
/** * user: 用戶佔用的時間片斷 * system: 系統佔用的時間片斷 */
複製代碼
process.cwd(); // 運行目錄
process.version; // Node版本
process.versions; // 運行環境版本
process.arch; // cpu架構
process.env.Node_ENV; // 環境 須要先設置
process.env.PATH; // 環境變量
process.env.USERPROFILE; // 管理員目錄路徑 不一樣環境方式不同 process.env.HOME
process.platform; // 平臺 win32 macos
複製代碼
process.argv; // 獲取運行參數,空格分隔可在數組中獲取到,默認會存在Node目錄和執行腳本的目錄兩個值。
process.argv0; // 獲取第一個值, 只有這一個api
process.pid; // 獲取運行的pid
process.ppid;
process.uptime; // 腳本運行時間
複製代碼
事件監聽在process
中提供的內容。這裏不會着重說明process
裏面到底有哪些事件,主要仍是看一看在NodeJS
裏面熟悉一下事件驅動編程以及發佈訂閱的模式。前端
process
是實現了emit
接口的。可使用on
監聽事件,內部提供了不少的事件,好比exit
,程序退出的時候執行。這裏綁定的事件只能執行同步代碼,是不能夠執行異步代碼的,這裏要注意。linux
process.on('exit', (code) => { // 退出時
console.log(code); // 0
})
process.on('beforeExit', (code) => { // 退出以前
console.log(code); // 0
})
複製代碼
手動退出,這種退出不會執行beforeExit
,並且exit
後面的代碼也不會執行,由於執行exit
就已經退出了。算法
process.exit();
複製代碼
process.stdout; // 是一個流,能夠對他進行讀寫操做。
process.stdout.write('123'); // 123
複製代碼
const fs = require('fs');
fs.createReadStream('text.txt').pipi(process.stdout); // 讀取文件輸出。
複製代碼
process.stdin; // 能夠拿到控制檯輸入的內容
process.stdin.pipe(process.stdout); // 輸入以後輸出
複製代碼
// 設置字符編碼
process.stdin.setEncoding('utf-8');
// 監聽readable事件,是否可讀也就是有無內容
process.stdin.on('readable', () => {
// 獲取輸入的內容
let chunk = process.stdin.read();
if (chunk !== null) {
process.stdout.write(chunk);
}
})
複製代碼
Node
中的內置模塊,能夠直接使用require
將它導入,他的主要做用就是處理文件的目錄和路徑。只須要調用不一樣的方法。path
至關於一個工具箱,只須要掌握它裏面提供的工具,也就是方法。macos
const path = require('path');
複製代碼
獲取路徑中基礎名稱編程
path.basename(__filename); // test.js
// 傳入第二個參數若是匹配會省略後綴,不匹配仍舊返回真實的後綴
path.basename(__filename, '.js'); // test
path.basename('/a/b/c'); // c
path.basename('/a/b/c/'); // c
複製代碼
獲取路徑中的目錄名稱api
path.dirname(__filename); // d:\Desktop\test
path.dirname('/a/b/c'); // /a/b
path.dirname('/a/b/c/'); // /a/b
複製代碼
獲取路徑中的擴展名稱數組
path.extname(__filename); // .js
path.extname('/a/b'); //
path.extname('/a/b/index.html.js.css'); // .css
path.extname('/a/b/index.html.js.'); // .
複製代碼
獲取路徑是不是絕對路徑瀏覽器
path.isAbsolute('a'); // false
path.isAbsolute('/a'); // true
複製代碼
拼接多個路徑片斷,還原成完整可用路徑
path.join('a/b', 'c', 'index.html'); // a/b/c/index.html
path.join('/a/b', 'c', 'index.html'); // /a/b/c/index.html
path.join('a/b', 'c', '../', 'index.html'); // a/b/index.html
複製代碼
返回一個絕對路徑
path.resove(); // 獲取絕對路徑
複製代碼
解析路徑
const obj = path.parse('/a/b/c/index.html');
/** * root: / * dir: /a/b/c * base: index.html * ext: .html * name: index */
複製代碼
序列化路徑,與parse
功能相反, 將對象拼接成完整的路徑。
path.format({
root: '/',
dir: '/a/b/c',
base: 'index.html',
ext: '.html',
name: 'index'
});
// /a/b/c/index.html
複製代碼
規範化路徑,將不可用路徑變爲可用路徑, 這個方法注意若是有轉譯字符會轉譯。
path.normalize('a/b/c/d'); // a/b/c/d
path.normalize('a//b/c../d'); // a/b/c../d
path.normalize('a\\/b/c\\/d'); // a/b/c/d
複製代碼
Buffer
通常稱爲緩衝區,能夠認爲由於Buffer
的存在讓開發者可使用js
操做二進制
。IO
行爲操做的就是二進制數據。NodeJS
中的Buffer
是一片內存空間。他的大小是不佔據V8
內存大小的,Buffer
的內存申請不是由Node
生成的。只是回收的時候是V8
的GC
進行回收的。
Buffer
是NodeJS
中的一個全局變量,無需require
就能夠直接使用。通常配合stream
流使用,充當數據的緩衝區。
alloc
能夠建立指定字節大小的Buffer
,默認沒有數據
allocUnsafe
建立指定大小的Buffer
可是不安全,使用碎片的空間建立Buffer
,可能存在垃圾髒數據,不必定是空的。
from
接收數據建立Buffer
在v6
版本以前是能夠經過實例化建立Buffer
對象的,可是這樣建立的權限太大了,爲了控制權限,就限制了實例化建立的方式。
// 建立Buffer
const b1 = Buffer.alloc(10);
const b2 = Buffer.allocUnsafe(10);
複製代碼
from
建立Buffer
能夠接收三種類型,字符串,數組,Buffer
。 第二個參數是編碼類型。
const b3 = Buffer.from('1');
const b4 = Buffer.from([1, 2, 3]);
複製代碼
Buffer
的一些常見實例方法。
fill: 使用數據填充Buffer
,會重複寫入到最後一位
write:向Buffer
中寫入數據,有多少寫多少,不會重複寫入。
toString: 從Buffer
中提取數據
slice: 截取Buffer
indexOf:在Buffer
中查找數據
copy: 拷貝Buffer
中的數據
Buffer
的靜態方法。
concat: 將多個Buffer
拼接成一個新的Buffer
isBuffer: 判斷當前數據是不是一個Buffer
Buffer
的split
方法實現。
Array.Buffer.splice = function(sep) {
let len = Buffer.form(sep).length;
let ret = [];
let start = 0;
let offset = 0;
while(offset = this.indexOf(sep, start) !== -1) {
ret.push(this.slice(start, offset))
start = offset + len;
}
ret .push(this.slice(start));
return ret;
}
複製代碼
在Node
中Buffer
和Stream
隨處可見,他們用於操做二進制數據。
fs
是一個內置的核心模塊,全部與文件相關的操做都是經過fs
來進行實現的,好比文件以及目錄的建立,刪除,信息的查詢或者文件的讀取和寫入。
若是想要操做文件系統中的二進制數據須要使用fs
模塊提供的API
,這個過程當中Buffer
和Stream
又是密不可分的。
介紹fs
模塊以前咱們首先須要介紹一下文件系統的基礎知識,好比權限位,標識符,文件描述符等。
權限是指當前的操做系統內不一樣的用戶角色對於當前的文件能夠執行的不一樣權限操做,文件的權限操做被分爲r
,w
,x
三種, r
是讀權限,w
是寫權限,x
是執行權限。若是用8進制的數字進行表示r
是4
,w
是2
,x
是1
,若是不具有該權限就是一個0
。
操做系統中將用戶分爲三類分別是文件的全部者,通常指的是當前用戶本身,再有就是文件的所屬組,相似當前用戶的家人,最後是其餘用戶也就是訪客用戶。
Node
中flag
表示對文件操做方式,好比是否可讀可寫。
r: 表示可讀
w: 表示可寫
s: 表示同步
+: 表示執行相反操做
x: 表示排他操做
a: 表示追加操做
fd
就是操做系統分配給被打開文件的標識,經過這個標識符文件操做就能夠識別和被追蹤到特定的文件。不一樣操做系統之間是有差別的,Node
爲咱們抹平了這種差別。
Node
每操做一個文件,文件描述符就會遞增一次,而且它是從3
開始的。由於0
,1
,3
已經被輸入,輸出和錯誤佔用了。後面咱們在使用fs.open
打開文件的時候就會獲得這個fd
。
fs
任何文件操做api
都有同步和異步兩種方式,這裏只演示異步API
,同步基本也相同
readFile: 從指定文件中讀取數據
const fs = require('fs');
const path = require('path');
fs.readFile(path.resolve('aaa.txt'), 'utf-8', (err, data) => {
console.log(err);
console.log(data);
})
複製代碼
writeFile: 向指定文件中寫入數據
fs.writeFile('bbb.txt', 'hello', {
mode: 438, // 操做位
flag: 'w+',
encoding: 'utf-8'
}, (err) => {
console.log(err);
})
複製代碼
appendFile: 追加的方式向指定文件中寫入數據
fs.appendFile('bbb.txt', 'hello', {}, (err) => {
console.log(err);
})
複製代碼
copyFile: 將每一個文件中的數據拷貝到另外一個文件
fs.copyFile('aaa.txt', 'bbb.txt', (err) => {
console.log(err);
})
複製代碼
watchFile: 對指定文件進行監控
fs.watchFile('bbb.txt', {
interval: 20 // 20ms監控一次
}, (curr, prev) => {
console.log(curr); // 當前信息
console.log(prev); // 前一次信息
if (curr.mtime !== prev.mtime) {
// 文件被修改了
}
})
fs.unwatchFile('bbb.txt'); // 取消監控
複製代碼
前面咱們使用了fs
實現了文件的讀寫操做,既然已經讀寫了就證實已經實現了文件的打開,爲何Node
還要單獨的提供打開關閉的api
呢?
由於readFile
和writeFile
的工做機制是將文件裏的內容一次性的所有讀取或者寫入到內存裏,而這種方式對於大致積的文件來說顯然是不合理的,所以須要一種能夠實現邊讀編寫或者邊寫邊讀的操做方式,這時就須要文件的打開、讀取、寫入、關閉看作是各自獨立的環節,因此也就有了open
和close
。
const fs = require('fs');
const path = require('path');
// open
fs.open(path.resolve('aaa.txt'), 'r', (err, fd) => {
console.log(err);
console.log(fd);
fs.close(fd, (err) => {
});
})
複製代碼
access: 判斷文件或目錄是否具備操做權限
fs.access('aaa.txt', (err) => {
console.log(err); // 存在錯誤就是沒有權限
})
複製代碼
stat: 獲取目錄及文件信息
fs.stat('aaa.txt', (err, stat) => {
console.log(stat); // size isFile(), isDirectory()
})
複製代碼
mkdir: 建立目錄
fs.mkdir('a/b/c', {
recursive: true, // 遞歸建立
}, (err) => {
console.log(err);
})
複製代碼
rmdir: 刪除目錄
fs.rmdir('a', {
recursive: true, // 遞歸刪除
}, (err) => {
console.log(err);
})
複製代碼
readdir: 讀取目錄中內容, 不會遞歸子目錄
fs.readdir('a', (err, files) => {
console.log(files);
})
複製代碼
unlink: 刪除指定文件
fs.unlink('a', (err) => {
console.log(err);
})
複製代碼
CommonJS
的出現是爲了解決前端模塊化,他的做者但願能夠倒逼瀏覽器們實現前端模塊化,可是因爲瀏覽器自己具有的單線程阻塞的特色,CommonJS
並不能適用於瀏覽器平臺。CommonJS
是一個超集,他是語言層面的規範,模塊化只是這個規範中的一個部分。
Node
中經過EventEmitter
類實現事件統一管理。實際開發中基本不多引入這個類。這個類大部分供內置模塊使用的, 好比fs
、http
都內置了這個模塊。
Node
是基於事件驅動的異步操做架構,內置events
模塊,模塊提供了EventEmitter
類,他的實例對象具有註冊事件和發佈事件刪除事件的常規操做。
on:添加當事件被觸發時調用的回調函數
emit: 觸發事件,按照註冊的順序調用每一個事件監聽器
once: 註冊執行一次的監聽器
off:移除特定的監聽器
const EventEmitter = require('events');
const ev = new EventEmitter();
ev.on('event', () => {
})
ev.emit('event');
複製代碼
流
並非NodeJS
首創的內容,在linux
系統中可使用ls | grep *.js
命令操做,其實就是將ls
命令獲取到的內容交給grep
去處理,這就是一個流操做。
使用流能夠從空間和時間上提高效率,NodeJS
誕生之初就是爲了提升IO
性能,其中最經常使用的文件系統和網絡他們就是流操做的應用者。
NodeJS
中流就是處理流式數據的抽象接口,NodeJS
中的stream
對象提供了用於操做流的對象。對於流來講只有多使用才能加深瞭解。
流的分段處理能夠同時操做多個數據chunk
,同一時間流無須佔據大內存空間。流配合管道,擴展程序會變得很簡單。
NodeJS
中內置了stream
模塊,它實現了流操做對象。Stream
模塊實現了四個具體的抽象。全部的流都繼承自EventEmitter
。
Readable: 可讀流,可以實現數據的獲取。
Writeable: 可寫流,可以實現數據的寫操做。
Duplex: 雙工流,便可度又可寫。
Tranform: 轉換流,可讀可寫,還能實現數據轉換。
const fs = require('fs');
const rs = fs.createReadStream('./a.txt');
const ws = fs.createWriteStream('./b.txt');
rs.pipe(ws);
複製代碼
生產供消費的數據流。
const rs = fs.createReadStream('./a.txt');
複製代碼
const { Readable } = require('stream');
const source = ['a', 'b', 'c'];
class MyReadable extends Readable {
constructor() {
super();
this.source = source;
}
_read() {
const data = this.source.shift() || null;
this.push(data);
}
}
const myreadable = new MyReadable(source);
myreadable.on('data', (chunk) => {
console.log(chunk.toString());
})
複製代碼
用於消費數據的流,響應。
const ws = fs.createWriteStream('./b.txt');
複製代碼
const { Writable } = require('stream');
class MyWriteable extends Writable {
constructor() {
super();
}
_write (chunk, en, done) {
process.stdout.write(chunk.toString());
process.nextTick(done);
}
}
const mywriteable = new MyWriteable();
mywriteable.write('yindong', 'utf-8', () => {
consoel.log('end');
})
複製代碼
const { Duplex } = require('stream');
class MyDuplex extends Duplex {
constructor(source) {
super();
this.source = source;
}
_read() {
const data = this.source.shift() || null;
this.push(data);
}
_write(chunk, en, next) {
process.stdout.write(chunk);
process.nextTick(next);
}
}
const source = ['a', 'b', 'c'];
const myDuplex = new MyDuplex(source);
mtDuplex.on('data', (chunk) => {
console.log(chunk.toString());
})
mtDuplex.write('yindong', () => {
console.log('end');
})
複製代碼
const { Transform } = require('stream');
class MyTransform extends Transform {
constructor() {
super();
}
_transform(chunk, en, cb) {
this.push(chunk.toString().toUpperCase());
cb(null);
}
}
const t = new MyTransform();
t.write('a');
t.on('data', (chunk) => {
console.log(chunk.toString());
})
複製代碼
鏈表是一種數據存儲結構。
在文件可寫流的write
方法工做的時候,有些被寫入的內容須要在緩衝區排隊等待的,並且遵循的是先進先出的規則,爲了保存這些排隊的數據,在新版的Node
中就採用了鏈表的結構來存儲這些數據。
相比較數組來講,鏈表的優點更明顯,在多個語言下,數組存放數據的長度是有上限的,數組在執行插入或者刪除操做的時候會移動其餘元素的位置,而且在JS
中數組被實現成了一個對象。因此在使用效率上會低一些。
固然這都是相對的,實際應用中數組的做用仍是很強大的。
鏈表是由一系列節點組成的集合。這裏的節點都稱爲Node
節點,每一個節點的身上都有一個對象的引用是指向下一個節點,將這些指向下一個節點的引用組合到一塊兒也就造成了一個鏈,對於鏈表結構來講咱們常聽到的會有不一樣類型,雙向鏈表,單向鏈表,循環鏈表。經常使用的通常是雙向鏈表。
斷言, 若是不符合,會中止程序,並打印錯誤
const assert = require('assert');
// assert(條件, 一段話)
function sum(a, b) {
assert(arguments.length === 2, '必須有兩個參數');
assert(typeof a === 'number', ‘第一個參數必須是數字’);
}
複製代碼
使用c語言寫的插件,在Node中使用。
多線程
一個程序就是一個進程,一個進程會有多個線程 進程和進程是嚴格隔離的,擁有獨立的執行空間。 同一個進程內的全部線程共享一套空間、代碼
成本高,速度慢,安全,進程間通訊麻煩,寫代碼簡單。
成本低,速度快,不安全,線程間通訊簡單,寫代碼複雜。
Child_Processes
, Cluster
, Process
。
獲取命令行參數
簽名,完成加密算法的
const cryptp = require("crypto");
let obj = cryto.createHash('md5');
obj.update('123');
console.log(obj.digest('hex')); // MD5 32位
複製代碼
系統相關
const os = require('os');
// 獲取cpu個數
os.cpus();
複製代碼
事件隊列
const Event = require('events').EventEmitter;
let ev = new Event();
// 綁定事件
ev.on('msg', function(a, b,c) {
console.log(a, b, c); // 12 , 3, 8
})
// 派發事件
ev.emit('msg', 12,3,8);
複製代碼
本身實現一個Events
:
class EventEmitter {
constructor() {
this._events = {};
}
on(eventName, callBack) {
if (this._events[eventName]) {
this._events[eventName].push(callBack);
} else {
this._events[eventName] = [callBack];
}
}
emit(eventName) {
this._events[eventName].forEach(fn => {
fn();
})
},
off(eventName, callBack) {
this._events[eventName] = this._events[eventName].filter(fn => fn !== callBack)
}
}
複製代碼
請求url
模塊
const url = require('url');
url.parse('url', true); // 會解析出url和參數,包含query-string的功能。
複製代碼
TCP
穩定 Net
UDP
快 UDP/Datagram
DNS/Domain
域名解析成ip
const dns = require('dns');
dns.resolve('baidu.com', (err, res) => {
})
複製代碼
基於net
的http
服務
const http = require('http');
const server = http.createServer((request, response) => {
// request 爲請求數據
// response 爲響應數據
// 設置返回值類型
res.writeHead(200, {'Content-type' : 'text/html'});
response.write = 'server start';
return response.end(); // 結束
});
server.listen(3000); // 服務監聽的端口號
複製代碼