【Node】經常使用基礎 API 整理

1、Debug 調試方法

Node 的調試方法有不少,主要分爲安裝 node-inspect 包調試、用 Chrome DevTools 調試和 IDE 調試,能夠在官網的 Docs Debugging Guide 查看安裝方法。html

下面介紹使用 Chrome DevTools 調試的方法,首先安裝 Chrome Extension NIM,打開 Inspect 入口頁面 chrome://inspectnode

寫一個簡單 debug.js 測試文件:webpack

// apiTest/debug.js 
console.log("this is debug test")
function test () {
  console.log("hello world")
}
test()
複製代碼

使用node --inspect-brk來啓動腳本,-brk至關於在程序入口前加一個斷點,使得程序會在執行前停下來web

$ node --inspect-brk apiTest/debug.js 
Debugger listening on ws://127.0.0.1:9229/44b5d11e-3261-4090-a18c-2d811486fd0a
For help, see: https://nodejs.org/en/docs/inspector
複製代碼

chrome://inspect 中設置監聽端口 9229(默認),就能夠看到能夠 debug 的頁面:chrome

(function (exports, require, module, __filename, __dirname) { 
console.log("this is debug test")
function test () {
  console.log("hello world")
}
test()
});
複製代碼

若是咱們使用node --inspect來啓動腳本,那整個代碼直接運行到代碼結尾,沒法進行調試,但此時 Node 還進程沒有結束,因此能夠在 http://127.0.0.1:9229/json/list 查詢 devtoolsFrontendUrl ,複製此 Url 到 Chrome 上進行調試。json

看到使用 Chrome DevTools 的調試方法仍是比較複雜的,一些 IDE 都支持直接斷點調試,推薦WebStorm、VScode。segmentfault

2、全局變量

在 Node 中經常使用的全局方法有 CommonJS、Buffer、process、console、timer 等,這些方法不須要 require引入 API 就能夠直接使用。後端

若是但願有屬性或方法能夠*「全局使用」*,那就將它掛載在 Node 的global對象上:api

global.gNum = 300
console.log(gNum); // 300
複製代碼

在 Node 中全部模塊均可以使用這些全局變量,如下就介紹 Node 中的全局變量數組

2.1 CommonJS 模塊

Node CommonJS 模塊規範根據實現了moduleexportsrequire模塊機制。Node 對每一個文件都被進行了模塊封裝,每一個模塊有本身的做用域,如在 debug 時看到的:

(function (exports, require, module, __filename, __dirname) { 
	// some code
});
複製代碼

模塊機制中的 __dirname__filenameexportsmodulerequire()這些變量雖然看起來是全局的,但其實它們僅存在於模塊範圍。須要注意的幾點是:

  • 模塊內部module變量表明模塊自己
  • 模塊提供require()方法引入外部模塊到當前的上下文中
  • module.exports屬性表明模塊對外接口,默認的快捷方式exports

簡單的使用方式以下:

/* common_exports.js */
exports.num = 100  
exports.obj = {
  a : 200
}
exports = {
  count : 300
}

/* common_require.js */
const mod = require('./common_exports')
console.log(mod) // { num: 100, obj: { a: 200 } }
console.log(mod.count)  // undefined
複製代碼

注意到上例中的mod.countundefined,這是由於exports只是module.exports的引用,能夠給exports添加屬性,但不能修改exports的指向。

更深刻的瞭解模塊機制能夠看 【Node】先後端模塊規範與模塊加載原理

2.2 process 進程對象

process 包含了進程相關的屬性和方法,Node 的 process 文檔 中的內容特別多,列舉幾個經常使用方法。

Node 進程啓動時傳遞的參數都在 process.arg數組中:

// process.js
const {argv , execPath} = process

argv.forEach((val, index) => {
  console.log(`${index}: ${val}`)
})
console.log(execPath)
複製代碼

能夠在執行 process.js 時傳遞其餘參數,這些參數都會保存在argv中:

$ node apiTest/process.js one=1 --inspect --version
0: /usr/local/bin/node
1: /Users/mobike/Documents/webProjects/testNode/apiTest/process.js
2: one=1
3: --inspect
4: --version
/usr/local/bin/node
複製代碼

process.argv第一個參數就是 process.execPath ,即調用執行程序 Node 的路徑,第二個參數時被執行的 JS 文件路徑,剩下的就是自定義參數。


process.env是包含運行環境各類參數的對象,能夠直接輸出env查看全部參數信息,也能夠輸出某個屬性:

const env = process.env
console.log(env.PATH) // /usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/Documents/webProjects/testNode/node_modules/.bin
console.log(env.SHELL) // /bin/zsh
複製代碼

在 webpack 打包過程當中經常使用process.env.NODE_ENV判斷生產環境或開發環境,process.env是沒有NODE_ENV這個屬性的,你能夠在系統環境變量中配置,也能夠在項目程序直接設置process.env.NODE_ENV=‘dev’


process.cwd()方法返回 Node.js 進程的當前工做目錄,和 Linus 命令$ pwd功能同樣:

// process.js
console.log(process.cwd()) // /Users/Documents/webProjects/testNode
複製代碼
$ node process.js
/Users/WebstormProjects/testNode
$ pwd
/Users/WebstormProjects/testNode

複製代碼

2.3 Timers 異步

Node 中的計時器方法與 Web 瀏覽器中的JS 計時器相似,但內部實現是基於 Node 的 Event Loop。Node 中的計時器有setImmediate()setTimeout()setInterval()

在 Node 中有一個輕量級的process.nextTick()異步方法,它是在當前事件隊列結束時調用, setImmediate()是當前 Node Event Loop 結束時當即執行,那執行順序有什麼區別呢?

下面舉例說明process.nextTick(fn)setImmediate(fn)setTimeout(fn,0)之間的區別:

// timer.js 
setImmediate(()=>{
  console.log("setImmediate")
});

setTimeout(()=>{
  console.log("setTimeout 0")
},0);

setTimeout(()=>{
  console.log("setTimeout 100")
},100);

process.nextTick(()=>{
  console.log("nextTick")
  process.nextTick(()=>{
    console.log("nextTick inner")
  })
});
複製代碼

看下執行結果:

$ node timer.js 
nextTick
nextTick inner
setTimeout 0
setImmediate
setTimeout 100
複製代碼

process.nextTick()中的回調函數最快執行,由於它將異步事件插入到當前執行隊列的末尾,但若是process.nextTick()中的事件執行時間過長,後面的異步事件就被延遲。

setImmediate()執行最慢,由於它將事件插入到下一個事件隊列的隊首,不會影響當前事件隊列的執行。當setTimeout(fn, 0)是在setImmediate()以前執行。

2.4 Buffer 二進制

Buffer 對象用於處理二進制數據流。JS 沒有處理二進制的功能,而 Node 中的一部分代碼是由 C++ 實現的,全部 Node 中的 Buffer 性能部分用 C++ 實現,非性能部分由 JS 封裝。

Buffer 實例相似整數數組,元素爲十六進制的兩位數(0~255),而且掛載在 global 對象上不須要 require就能使用。

最新的 Buffer API 使用Buffer.alloc(length, value)建立固定長度爲 length 的 Buffer 實例,value 默認填充 0,使用Buffer.from()將其它類型數據轉爲 Buffer:

console.log(Buffer.alloc(5))        // <Buffer 00 00 00 00 00>
console.log(Buffer.alloc(5, 44))    // <Buffer 2c 2c 2c 2c 2c>
console.log(Buffer.from([3, 4, 5])) // <Buffer 03 04 05>
console.log(Buffer.from('test'))    // <Buffer 74 65 73 74>
console.log(Buffer.from('測試'))     // <Buffer e6 b5 8b e8 af 95>
複製代碼

注意到字符串轉 Buffer 時英文佔一位,中文佔三位,而不是四位,當中文亂碼的時能夠考慮沒有正確讀取 Buffer 流。

Buffer 類提供幾個靜態方法,Buffer.byteLength()計算長度,Buffer.isBuffer()作驗證,Buffer.concat()拼接 Buffer 實例:

const buf1 = Buffer.from([3, 4, 5])
const buf2 = Buffer.from('test')

console.log(Buffer.byteLength('test'))   // 4
console.log(Buffer.byteLength('測試'))    // 6 
console.log(Buffer.isBuffer('test'))     // false
console.log(Buffer.isBuffer(buf1))       // true
console.log(Buffer.concat([buf1, buf2])) // <Buffer 03 04 05 74 65 73 74>

複製代碼

除此以外,Buffer 實例也有經常使用的屬性和方法,相似 JS 中的 String,有lengthtoString('base64')equals()indexOf()等。

以上就是 Node 全局變量的概述,其餘的 API 或內置模塊都須要· require('xxx')引入使用,咱們能夠在 nodejs.cn 中查看關於 Global API 更詳細的介紹。

3、基礎 API

3.1 path 路徑相關

path 是處理和路徑相關問題的內置 API,能夠直接require('path')使用。如下示例經常使用的 path 方法。

對路徑的處理經常使用path.normalize()規範路徑、path.join()拼接路徑,以及使用path.resolve()將相對路徑解析爲絕對路徑:

const path = require('path')
console.log(
  path.normalize('//asd\/das'), // /asd/das
  path.join('user', 'local'),   // user/local
  path.resolve('./'))           // /Users/Documents/webProjects/testNode/apiTest
複製代碼

解析某個路徑,能夠用path.basename()獲得文件名稱,path.extname()獲得後綴擴展名,path.dirname()獲得目錄名:

const path = require('path')
const filePath = 'webProjects/testNode/apiTest/path.js'
console.log(
  path.basename(filePath), // path.js 
  path.extname(filePath)   // .js 
  path.dirname(filePath),  // webProjects/testNode/apiTest
)
複製代碼

以上解析路徑方法獲得某個值,還可使用path.parse()徹底解析路徑爲一個對象,path.format()反向操做:

let sp = path.parse(filePath)
console.log(sp)
// { root: '',
// dir: 'webProjects/testNode/apiTest',
// base: 'path.js',
// ext: '.js',
// name: 'path' }
console.log(path.format(sp))
// webProjects/testNode/apiTest/path.js
複製代碼

除此以外,還有對於系統路徑的操做,使用path.sep取得路徑分隔符,路徑片斷分隔符,POSIX 上是/, Windows 上是\path.delimiter取得系統路徑定界符,POSIX 上是:,Windows 上是; ,示例以下:

console.log(filePath.split(path.sep)) 
// [ 'webProjects', 'testNode', 'apiTest', 'path.js' ]

console.log(process.env.PATH) // 系統路徑配置
// /usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

console.log(process.env.PATH.split(path.delimiter))
// [ '/usr/local/bin', '/usr/bin', '/bin', '/usr/sbin', '/sbin' ]
複製代碼

以上就是 Node 對路徑的經常使用操做,須要注意的是,在獲取路徑時有幾種方式,獲得的路徑是不一樣的:

  • __dirname__filename:老是返回文件絕對路徑;
  • process.cwd()$ pwd :返回執行 Node 命令的文件夾;
  • path.resolve('./'):是相對 Node 啓動文件夾,在require()./是相對於當前文件夾;

3.3 events 事件

大部分 Node API 都採用異步事件驅動,全部能觸發事件對象都是 EventEmitter 類的實例,經過 EventEmitter.on()綁定事件,而後經過 EventEmitter.emit() 觸發事件。

// apiTest/events.js
const Events = require('events')

class MyEvents extends Events{
}
const event = new MyEvents()

event.on('test-event',()=>{
  console.log('this is an event')
})

event.emit('test-event')
setInterval(()=>{
  event.emit('test-event')
},500)
複製代碼

執行以上代碼會一直連續處罰 test-event 事件,固然還能夠傳遞事件參數,而且能夠傳遞多個參數。修改上訴代碼以下:

event.on('test-event', (data, time) => {
  console.log(data,time)
})
event.emit('test-event', [1, 2, 3], new Date())
複製代碼
$ node apiTest/events.js
[ 1, 2, 3 ] 2019-04-23T07:28:00.420Z
複製代碼

同一個事件監聽器能夠綁定多個事件,觸發時按照綁定順序加入執行隊列,而且可使用EventEmitter.removeListener()刪除監聽器的事件:

function fn1 () {
  console.log('fn1')
}
function fn2 () {
  console.log('fn2')
}
event.on('multi-event',fn1)
event.on('multi-event',fn2)

setInterval(()=>{
  event.emit('multi-event')
},500)
setTimeout(()=>{
  event.removeListener('multi-event', fn2)
}, 600)
複製代碼
$ node apiTest/events.js
[ 1, 2, 3 ] 2019-04-23T07:39:11.624Z
fn1
fn2
fn1
fn1
...
複製代碼

3.4 fs 文件系統

Node 文件模塊經過require('fs)使用,所用方法都有同步和異步方法。

文件系統中的異步方法,第一個參數保留給異常,操做成功時參數值爲nullundefined,最後一個參數就是回調函數。例如讀取文件的fs.readFile()和寫文件的fs.writeFile()示例以下:

const fs = require('fs')

fs.readFile('./apiTest/fs.js', (err, data) => {
 if (err) throw err
 console.log('readFile done!!!')
})

fs.writeFile('./apiTest/fs.txt', 'this is test file', {
 encoding: 'utf8'
}, (err) => {
 if (err) throw err
 console.log('writeFile done!!!')
})
複製代碼

推薦 nodejs.cn 中的 Docs API 中文版查看更多 Node API 的使用。


加油呢少年~

相關文章
相關標籤/搜索