升級后的Node.js v6 長期支持版 Boron 中的10個主要功能

gang603780 7年前發布 | 21K 次閱讀 Node.js Node.js 開發

正如我們之前在 Node.js v6.9.0 發布簡報中所述,Node.js v6 的版本規劃,本周進入到了長期支持(服務)版。對于 Node.js 和用戶來說,這都是重要的一步。這個版本增加了很多有用的功能。

接著你可能想知道,這個最新發布的 v6 長期支持版和 Node.js v4 長期支持版對比來看,那些新增的最好的功能是什么。Luckily!我們已經收集了10個最有用和有趣的新功能,都羅列在下面了。包括像 DevTools Inspector、未處理的 Promise 拒絕警告,還有 進程警告 API。

1. DevTools Inspector 集成

去年,Chromium 團隊找到 Node 核心團隊,問他們是否對,重新使用和 Blink 捆綁的 DevTools debugger 來和 Node.js 交互的這種方式,感興趣。盡管Node.js debugger 非常的實用, 這些年它也沒有被很好的關注,現代瀏覽器中的 Javascript debuggers 已經比 Node 自己能夠提供的先進很多了。

在 Node.js 6.3.0 中,Google 的 v8_inspector 協議來自 Blink,并隨 Node 提供。這個功能仍然被 Node 核心團隊視為試驗性的,這意味著,它還沒有被全面的記錄,并且可能在未來的版本中被移除,不必經過淘汰周期。但是呢,鑒于這個工具的普及和強大,上面的情況也并不可能發生。最可能的結果是,舊的 debugger 最終被新功能完全取締。

當 Node.js 以 --inspect 命令后參數(帶可選的端口號)運行的時候,控制臺會打印出 chrome-devtools:// 。在 Chrome 瀏覽器中輸入這個鏈接,就會直接在進程中發起一個遠程調試連接。添加 --debug-brk 命令行捕獲EventEmitter上的偵聽器的名稱捕獲EventEmitter上的偵聽器的名稱參數,就會在你的應用程序的第一行打斷點,這樣你就能夠使用調試器啦。你可以使用 Chrome 的 DevTool 來調試你的 Node 應用程序,就和你調試前端 JavaScript 一樣,包括實時代碼編輯和完全異步堆棧調用功能等。閱讀 Paul Irish 的文章 ,了解 Node.js v6 LTS 現有特性的更多細節。

這個新協議不是Chrome獨有的,它是一種WebSockets JSON協議,具有良好的文檔,已經在多個客戶端和服務器上實現。Visual Studio Code 編輯器已經 宣布 已經支持了這個實驗特性,你也可以在 命令行 界面去使用它。

2.捕獲EventEmitter上的偵聽器的名稱

eventNames() 方法,在 Node.js 6.0.0 添加, 會返回一個給定 EventEmitter 對象上的,由用戶回調監聽的,所有事件的名稱。除非你使用了內部的 _events 屬性,不然以前這種功能是不可用的。

找到正在被監聽的事件的名稱,對于檢測一個事件何時不被監聽的,非常有用。這樣就允許附加監聽器來處理那些還沒有被處理的事件,或忽略那些不再需要的針對一些事件的工作。

3. 大修 Buffer 構造函數API

Buffer 構造函數 API 被大改啦。廢棄了舊的 new Buffer(...) , 使用 Buffer.from() 和 Buffer.alloc() 來完美的替換。這些 API 在 v.5.10.0 的時候增加到了 Node 核心,同時運行兩個不同的用法: Buffer.from() 從類數組(比如一個數組,字符串,或者其他 Buffer) 中創建一個 Buffer, Buffer.alloc() 創建一個指定大小的,0填充的 Buffer 。

此外在 v5.10.0,增加了這個 --zero-fill-buffers 命令行標識 ,在一個 Node 應用程序中,讓所有的 新創建的 Buffers 都被自動強制的 0填充。

而這個新的 Buffer 構造特征集,提供一個更清晰的接口,來使應用程序不可能意外地通過不正確的緩沖區創建而泄漏舊內存空間.

在 Node.js 文檔中,使用普通的 Buffer() 構造函數被遺棄了,同時解釋了新的 API 被使用的原因。在 Node.js 未來的版本中,當一個 Buffer 被使用 舊的 構造器被創建的時候,一個警告將被打印到標準錯誤中。

4. 未處理的 Promise 拒絕警告

對 Promise 經常挑剔的原因之一,就是錯誤能夠容易被吞掉并且忽略。從 io.js 和 Node.js v5 開始, ’unhandledRejection’ 和 ’rejectionHandled’ 事件,被 process 對象發出的,已經可以用來洞悉沒有被處理的 Promise rejections。由于 Promise 錯誤處理的語義,它不可能和 uncaughtException 一樣清晰的表示一個 rejection 可能被存儲并在最后處理。事實上,對于 unhandledRejection 事件名稱,早期的候選之一就是 possiblyUnhandledRejection 。但是現在慣用的 Promise 用法表明這是一種反模式,rejection 處理函數應該被放在接近其創建的 Promise 上,而不是直接放在構造器上,或直接放在后面。

自從 Node.js v6.6.0, 這個 unhandledRejection 事件也會引起一個警告會被打印到標準錯誤上。

$ node
> new Promise((resolve, reject) => { setTimeout(() => { reject(new Error('Whoa!')) }, 100) })
Promise { <pending> }
> (node:35449) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Whoa!

這個行為可以在帶有 --no-warnings 命令行參數的時候關閉,或者在帶有 --trace-warnings 命令行參數的時候創造更多的信息。這樣,你就可以追蹤錯誤代碼的位置了。

$ node
$ node --trace-warnings
> new Promise((resolve, reject) => { setTimeout(() => { reject(new Error('Whoa!')) }, 100) })
Promise { <pending> }
> (node:35484) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Whoa!
    at emitPendingUnhandledRejections (internal/process/promises.js:57:27)
    at runMicrotasksCallback (internal/process/next_tick.js:61:9)
    at _combinedTickCallback (internal/process/next_tick.js:67:7)
    at process._tickDomainCallback (internal/process/next_tick.js:122:9)

由于一個 rejection 處理程序 能夠在 Promise 創建之后被 catch() 方法處理,這個警告將不會被發射,直到這個 rejection 之后的事件循環的下一個刻度之后。

$ node
> function resolver (resolve, reject) { setTimeout(() => { reject(new Error('Whoa!')) }, 100) }
undefined
> // rejection handler attached on same tick:
> p = new Promise(resolver); p.catch((err) => { console.error(err) });
Promise { <pending> }
> Error: Whoa!
    at Timeout.setTimeout (repl:1:81)
    at ontimeout (timers.js:365:14)
    at tryOnTimeout (timers.js:237:5)
    at Timer.listOnTimeout (timers.js:207:5)
> // rejection handler added on a later tick, causing an additional ‘rejectionHandled’ event
> p = new Promise(resolver)
Promise { <pending> }
> (node:35560) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Whoa!
> p.catch((err) => { console.error(err) });
Promise { <pending> }
> (node:35560) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 1)
Error: Whoa!
    at Timeout.setTimeout (repl:1:81)
    at ontimeout (timers.js:365:14)
    at tryOnTimeout (timers.js:237:5)
    at Timer.listOnTimeout (timers.js:207:5)

5. 快速和安全的臨時目錄創建

fs.mkdtemp() API 在 v5.10.0被加到到了 Node 核心中,提供一個有保障的方式來創建一個獨一無二的臨時目錄。這個 API 生成6個隨機的字符附加到必須的目錄 prefix 參數之后。這個功能以前可能出現在用戶創建的模塊中,像 unique-temp-dir ,盡管和使用本地系統調用和不都是有保障的安全相比,這個功能的 JavaScript 實現的所有的痛苦都來自性能問題。

這個 API 允許你結合系統默認的臨時目錄,來完全確保沒有目錄沖突。將此作為Node.js中的標準化特性,是保證API對于需要使用臨時目錄的任何模塊或應用程序都是一致的。

6. 定時攻擊預防

crypto.timingSafeEqual() API 在 v6.6.0 中被加入到了 Node.js 核心中,來避免 定時攻擊 。這個 API 允許比較,卻不會泄漏關于比較的定時信息,而這個信息可能會導致惡意方能給推斷被比較的值。通過將這個 API添加到 crypto 模塊,來允許 它 在 assert 之外使用。一般說來,如果你需要比較兩個值,一個來自用戶的輸入,另一個是一個秘密(或者來自一個秘密),就可以使用這個 API。

7.進程警告 API

這個新的進程警告 API 是在 v6.0.0 被添加的,并且增加對被 Node.js 發射的進程警告的監聽能力,提供一個 API 來覆蓋默認的處理函數,例如被用在自定義的日志系統。具體來說,如果你正在使用一個自定義的 JSON 日志。你現在可以捕獲 Node 核心警告,并讓它們作為 JSON 被記錄。

這個 API 還能夠被非核心的代碼使用,來適當的發射非重大的警告。例如

process.emitWarning('Something Happened!', 'CustomWarning'); 
// 或者
process.emitWarning('This API is deprecated', 'DeprecationWarning');

目前,Node 核心發射的: DeprecationWarning ,當 “運行時棄用的” 核心API被使用的時候被使用。 PromiseRejectionHandledWarning , 當一個 Promise 被拒絕但是沒有拒絕處理程序附加來接受它的時候被使用。* MaxListenersExceededWarning , 當一個 EventListener 有超過 maxListeners 數量(默認10個)的時候被使用,這可能是內存泄漏的提示,監聽器被添加卻沒有在不再需要的時候移除。

警告任然被打印到標準錯誤,但是也是自定義的用戶區錯誤。

$ node -e 'process.emitWarning("Something Happened!", "CustomWarning");'
(node:33526) CustomWarning: Something Happened!

請注意,警告輸出現在也包含這個進程的 ID。

此外,這個 API 還帶來了一些新的命令行參數來調整警告輸出:

  • --no-warnings 禁止打印到標準錯誤 (內部的 ’警告’ 事件任然發射)
  • --no-deprecation 禁止打印不贊成使用警告到標準錯誤 (內部的 ’警告’ 事件任然發射)
  • --trace-warnings 堆棧跟蹤打印到標準錯誤,鏡像錯誤輸出,對于從您自己的代碼或依賴關系中查找使用已棄用的API的位置很有用。
  • --trace-deprecation 讓棧追蹤只對反對警告
  • --throw-deprecation 對待一個反對警告作為一個拋出錯誤
$ node -e 'require("sys")'
(node:33668) DeprecationWarning: sys is deprecated. Use util instead.
$ node --no-deprecation -e 'require("sys")'
$ node --trace-deprecation -e 'require("sys")'
(node:33681) DeprecationWarning: sys is deprecated. Use util instead.
    at sys.js:10:6
    at NativeModule.compile (bootstrap_node.js:497:7)
    at Function.NativeModule.require (bootstrap_node.js:438:18)
    at Function.Module._load (module.js:426:25)
    at Module.require (module.js:497:17)
    at require (internal/module.js:20:19)
    at [eval]:1:1
    at ContextifyScript.Script.runInThisContext (vm.js:25:33)
    at Object.exports.runInThisContext (vm.js:77:17)
    at Object.<anonymous> ([eval]-wrapper:6:22)
$ node --throw-deprecation -e 'require("sys")'
internal/process/warning.js:45
      throw warning;
      ^

DeprecationWarning: sys is deprecated. Use util instead.
    at sys.js:10:6
    at NativeModule.compile (bootstrap_node.js:497:7)
    at Function.NativeModule.require (bootstrap_node.js:438:18)
    at Function.Module._load (module.js:426:25)
    at Module.require (module.js:497:17)
    at require (internal/module.js:20:19)
    at [eval]:1:1
    at ContextifyScript.Script.runInThisContext (vm.js:25:33)
    at Object.exports.runInThisContext (vm.js:77:17)
    at Object.<anonymous> ([eval]-wrapper:6:22)

8.符號鏈接保存

指示模塊加載器在解析和緩存模塊時保留符號鏈接。打開的時候,當設置 __dirname 和 __filename 以及在使用位置,使用 require() 而不是使用鏈接文件的“realpath”來解析其他模塊的路徑時,會保留模塊路徑。

這個功能剛開始討論的時候 ,是使用下面行為的例子,當符號鏈接沒有被保存的時候,行為是不工作的。

解析正確:

app
    index.js //require("dep1")
    node_modules
        dep1
            index.js //require("dep2")
        dep2
            index.js //console.log('fun!'):

不解析,用戶期望的應該是這個鏈接在一個恰當的位置

app
    index.js //require("dep1")
    node_modules
        dep1 -> ../../dep1
        dep2
            index.js
dep1
    index.js //require("dep2")

當開發使用對等依賴,可以被相互連接而不是手動復制,才尋求這個行為。

在以為這對生態系統的影響更多的是積極的,這樣的錯誤思想下,保留符號鏈接在 Node.js v6.0.0 中是默認開啟的。不幸的是,通過 bug 回報發現,一些使用案例中,新功能會中斷應用程序,或基于 Node 以前的運行情況的假設下,新功能還會導致低性能。你可以在 原帖 中了解更多關于這個問題,這個問題在 v6.0.0 發布之后非常活躍,并且如何解決這個匯報的問題是討論的重點。

最后, --preserve-symlinks 命令行參數被添加,并且在 v6.2.0 中恢復了默認行為。 而核心團隊也表明, --preserve-symlinks 現在最好的解決辦法,迄今為止,還沒有好的建議。

9. 直接通過 Node.j s的 V8 引擎性能分析

這個新的命令后參數 --prof-process 是在 Node.js v5.2.0 增加的,來給 V8 引擎性能簡介運行內置的格式化工具。通過使用直接傳遞給 V8 的 --prof 命令行參數,這些配置已經可以在 Node.js 中使用一段時間了。

當一個程序以 --prof 運行的時候,在應用程序內部,一個例如 isolate-0x102004c00-v8.log (這個八進制數每次運行都會改變) 名字的文件就會為每一個 "isolate"(一個擁有自己的堆的獨立的 V8 虛擬機實例) 創建(子進程或者使用了 vm 模塊,都可能引起應用程序去使用一個或以上的 isolate)。

可惜的是,這些分析日志文件是人類不可讀的,并且非常冗長:

$ node --prof ./map-bench.js
$ wc isolate-0x*.log
    3375    4571  419868 isolate-0x102004c00-v8.log
    3801    4968  514577 isolate-0x102801000-v8.log
    4319    5493  628883 isolate-0x103800a00-v8.log
   11495   15032 1563328 total

V8還附帶了它所謂的“tick processor”,它能夠解析這些文件并產生人類可讀和有用的輸出。以前,你可能不得不從 npm 去安裝例如 tick ,但是,對于作者和用戶來說,問題是這個 tick processor 需要跟上 V8 的每個版本,來從 V8 產生的日志文件中得到有用的輸出。在 Node.js 中帶著一個 tick processor 能夠解決這樣的需求,并且還為用戶帶來一個方便有用的代碼分析工具。

$ node --prof-process isolate-0x103800a00-v8.log
Statistical profiling result from isolate-0x103800a00-v8.log, (2819 ticks, 201 unaccounted, 0 excluded).

 [Shared libraries]:
   ticks  total  nonlib   name
     17  0.6%        /usr/lib/system/libsystem_platform.dylib
      6   0.2%        /usr/lib/system/libsystem_c.dylib

 [JavaScript]:
   ticks  total  nonlib   name
    112 4.0%    4.0%  Stub: StringAddStub_CheckNone_NotTenured
     47  1.7%    1.7%  Stub: CEntryStub
     43  1.5%    1.5%  LazyCompile: *runFakeMap /home/rvagg/node/benchmark/es/map-bench.js:49:20

…

 [C++]:
   ticks  total  nonlib   name
    276 9.8%    9.9%  v8::internal::NameDictionaryBase<v8::internal::NameDictionary, v8::internal::NameDictionaryShape>::FindEntry(v8::internal::Handle<v8::internal::Name>)
    239 8.5%    8.5%  v8::internal::StringTable::LookupKey(v8::internal::Isolate*, v8::internal::HashTableKey*)
    127 4.5%    4.5%  v8::internal::HashTable<v8::internal::NameDictionary, v8::internal::NameDictionaryShape, v8::internal::Handle<v8::internal::Name> >::Rehash(v8::internal::Handle<v8::int

…

 [Summary]:
   ticks  total  nonlib   name
    372   13.2%   13.3%  JavaScript
   2223   78.9%   79.5%  C++
     43  1.5%    1.5%  GC
     23  0.8%        Shared libraries
    201 7.1%        Unaccounted

…

(輸出已經做了大量修剪,只保留有用的)

你不僅可以用這個輸出查看哪一部分的代碼占用虛擬機時間最多,知道它們被調用的地方,還可以直觀的了解到虛擬機是如何對待你的代碼的。舉個例子,JavaScript函數名旁邊的 * 表明這個代碼被 V8引擎優化了。更多的關于如何去讀取這個數據可以在 V8 wiki 中找到。

當然,如果你想在 生產環境運行時,進行分析,你可以嘗試 NodeSource 的 N|Solid 來以圖形格式查看類似數據。

10. 進程 CPU 使用情況

這個 process.cpuUsage() API 是在 v6.1.0 時加入 Node 核心的。返回一個包含用戶和系統當前微秒下進程的 CPU 時間。

這個API允許通過檢查API的兩次調用之間的總時間差,以及一些額外的分支來推斷CPU處于活動狀態的時間。

 

來自:http://www.zcfy.cc/article/the-10-key-features-in-node-js-v6-lts-boron-after-you-upgrade-1831.html

 

 本文由用戶 gang603780 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!