由於之前學習Node.js並無真正意義上的去學習它,而是粗略的學習了npm的經常使用命令和Node.js一些模塊化的語法,所以昨天花了一天的時間看了《Node.js開發指南》一書。經過這本書卻是讓我對Node.js的認識更爲全面,但因爲這本書出版時間過早,有些API已經發生了變化或已經被廢棄,而對於學習Node.js來講,核心部分又是最爲重要的一環,所以我配合官方文檔對這本書的第四章-Node.js核心進行了總結與梳理,因爲水平有限,若有疏漏與錯誤,請指正。node
核心模塊是Node.js的心臟,主要是有一些精簡高效的庫組成(這方面和Python有很大的類似之處),爲Node.js提供了基礎的API。主要內容包括:npm
Node.js核心入門(一)編程
全局對象
經常使用工具
事件機制數組
Node.js核心入門(二)瀏覽器
文件系統訪問
HTTP服務器與客戶端服務器
全局對象我想學過JavaScript的都知道在瀏覽器是window,在程序的任何地方均可以訪問到全局對象,而在Node.js中,這個全局對象換成了global,全部的全局變量(除了global自己)都是global對象的屬性。而咱們在Node.js中可以直接訪問的對象一般都是global的屬性,如:console,process等。架構
global最根本的做用就是做爲全局變量的宿主。按照ECMAScript規範,知足如下條件的變量即爲全局變量:異步
當咱們定義一個全局變量的時候,這個全局變量會自動成爲全局變量的屬性。async
process 對象是一個全局變量,它提供當前 Node.js 進程的相關信息,以及控制當前 Node.js 進程。一般咱們在寫本地命令行程序的時候,少不了和它打交道。下面是它的最經常使用的成員方法:模塊化
1.process.argv
process.argv 屬性返回一個數組,這個數組包含了啓動Node.js進程時的命令行參數。第一個元素爲process.execPath,第二個元素爲當前執行的JavaScript文件路徑,剩餘的元素爲其餘命令行參數。
例如存儲一個名爲argv.js的文件:
// print process.argv process.argv.forEach((val, index) => { console.log(`${index}: ${val}`); });
則命令行運行時這樣的:
$ node process-args.js one two=three four 0: /usr/local/bin/node 1: /Users/mjr/work/node/process-args.js 2: one 3: two=three 4: four
2.process.stdout
process.stdout是標準輸出流,一般咱們使用的console.log()輸出打印字符,而process.stdout.write()函數提供了更爲底層的接口。
process.stdout.write('請輸入num1的值:');
3.process.stdin
process.stdin是標準輸入流,初始時它是暫停的,要想從標準輸入讀取數據,咱們必須恢復流,並手動編寫流的事件響應函數。
/*1:聲明變量*/ var num1, num2; /*2:向屏幕輸出,提示信息,要求輸入num1*/ process.stdout.write('請輸入num1的值:'); /*3:監聽用戶的輸入*/ process.stdin.on('data', function (chunk) { if (!num1) { num1 = Number(chunk); /*4:向屏幕輸出,提示信息,要求輸入num2*/ process.stdout.write('請輸入num2的值'); } else { num2 = Number(chunk); process.stdout.write('結果是:' + (num1 + num2)); } });
4.process.nextTick(callback[, ...args])
...args <any> 調用 callback時傳遞給它的額外參數
process.nextTick()方法將 callback 添加到"next tick 隊列"。 一旦當前事件輪詢隊列的任務所有完成,在next tick隊列中的全部callbacks會被依次調用。
這種方式不是setTimeout(fn, 0)的別名。它更加有效率,所以別用setTimeout去代替process.nextTick。事件輪詢隨後的ticks 調用,會在任何I/O事件(包括定時器)以前運行。
console.log('start'); process.nextTick(() => { console.log('nextTick callback'); }); console.log('scheduled'); // start // scheduled // nextTick callback
4.console
console 模塊提供了一個簡單的調試控制檯,相似於 Web 瀏覽器提供的 JavaScript 控制檯。該模塊導出了兩個特定的組件:
好比全局下的常見的console實例:
console.log('hello,world'); // hello,world console.log('hello%s', 'world'); // helloworld console.error(new Error('錯誤信息')); // Error: 錯誤信息 const name = '描述'; console.warn(`警告${name}`); // 警告描述 console.trace() // 向標準錯誤流輸出當前的調用棧
常見的Console類:
const out = getStreamSomehow(); const err = getStreamSomehow(); const myConsole = new console.Console(out, err); myConsole.log('hello,world'); // hello,world myConsole.log('hello%s', 'world'); // helloworld myConsole.error(new Error('錯誤信息')); // Error: 錯誤信息 const name = '描述'; myConsole.warn(`警告${name}`); //警告描述
util 模塊主要用於支持 Node.js 內部 API 的需求。 大部分實用工具也可用於應用程序與模塊開發者,用於彌補核心JavaScript的功能的不足。它的能夠這樣調用:
const util = require('util');
1.util.inspect(object[, options])
util.inspect() 方法返回 object 的字符串表示,主要用於調試和錯誤輸出。 附加的 options 可用於改變格式化字符串的某些方面。它至少接受一個參數objet,即要轉換的參數,而option則是可選的,可選內容以下:
例如,查看 util 對象的全部屬性:
const util = require('util'); console.log(util.inspect(util, { showHidden: true, depth: null }));
2.util.callbackify(original)
util.callbackify(original)方法將 async 異步函數(或者一個返回值爲 Promise 的函數)轉換成遵循 Node.js 回調風格的函數。 在回調函數中, 第一個參數 err 爲 Promise rejected 的緣由 (若是 Promise 狀態爲 resolved , err爲 null ),第二個參數則是 Promise 狀態爲 resolved 時的返回值。例如:
const util = require('util'); async function fn() { return await Promise.resolve('hello world'); } const callbackFunction = util.callbackify(fn); callbackFunction((err, ret) => { if (err) throw err; console.log(ret); }); // hello world
注意:
function fn() { return Promise.reject(null); } const callbackFunction = util.callbackify(fn); callbackFunction((err, ret) => { // 當Promise的rejecte是null時,它的Error與原始值都會被存儲在'reason'中。 err && err.hasOwnProperty('reason') && err.reason === null; // true });
events是Node.js最重要的模塊,緣由是Node.js自己架構就是事件式的,大多數 Node.js 核心 API 都採用慣用的異步事件驅動架構,而它提供了惟一的接口,所以堪稱Node.js事件編程的及時。events 模塊不只用於用戶代碼與 Node.js 下層事件循環的交互,還幾乎被全部的模塊依賴。
全部能觸發事件的對象都是 EventEmitter 類的實例。 這些對象開放了一個 eventEmitter.on() 函數,容許將一個或多個函數綁定到會被對象觸發的命名事件上。 事件名稱一般是駝峯式的字符串,但也可使用任何有效的 JavaScript 屬性名。對於每一個事件, EventEmitter支持若干個事件監聽器。當事件發射時,註冊到這個事件的事件監聽器被依次調用,事件參數做
爲回調函數參數傳遞。
例如:
const EventEmitter = require('events'); class MyEmitter extends EventEmitter {} const myEmitter = new MyEmitter(); // eventEmitter.on() 方法用於註冊監聽器 myEmitter.on('event', () => { console.log('觸發了一個事件!'); }); // eventEmitter.emit() 方法用於觸發事件 myEmitter.emit('event');
下面讓咱們來看看EventEmitter最經常使用的API:
-EventEmitter.on(event, listener) 方法能夠添加 listener 函數到名爲 eventName 的事件的監聽器數組的末尾。不會檢查 listener 是否已被添加。屢次調用並傳入相同的 eventName 和 listener 會致使 listener 被添加與調用屢次。
-emitter.prependListener(eventName, listener)方法能夠添加 listener 函數到名爲 eventName 的事件的監聽器數組的開頭。 不會檢查 listener 是否已被添加。 屢次調用並傳入相同的 eventName 和 listener 會致使 listener 被添加與調用屢次。
-eventEmitter.emit() 方法容許將任意參數傳給監聽器函數。當一個普通的監聽器函數被 EventEmitter 調用時,標準的 this 關鍵詞會被設置指向監聽器所附加的 EventEmitter。
// 實例: const myEE = new EventEmitter(); myEE.on('foo', () => console.log('a')); myEE.prependListener('foo', () => console.log('b')); myEE.emit('foo'); // 打印: // b // a
server.once('connection', (stream) => { console.log('首次調用!'); });
const callback = (stream) => { console.log('有鏈接!'); }; server.on('connection', callback); // ... server.removeListener('connection', callback);
const callback = (stream) => { console.log('有鏈接!'); }; server.on('connection', callback); // ... server.removeListener('connection', callback);
EventEmitter 定義了一個特殊的事件 error ,它包含了「錯誤」的語義,咱們在遇到異常的時候一般會發射 error 事件。當 error被髮射時,EventEmitter規定若是沒有響
應的監聽器,Node.js 會把它看成異常,退出程序並打印調用棧。咱們通常要爲會發射 error 事件的對象設置監聽器,避免遇到錯誤後整個程序崩潰。
var events = require('events'); var emitter = new events.EventEmitter(); emitter.emit('error');
大多數狀況下,咱們不會直接使用EventEmitter,而是在對象中繼承它,包括fs,http在內的只要是支持事件響應的核心模塊都是EventEmitter的子類。這樣作的緣由有如下兩個: