Node.js 8 說明
原PPT地址
主要內容
- 5月30日發布 Node 8.0.0。
- 8.x (LTS) 的 code name 是 Carbon。
- ES2017 features 全部可以使用, 除了 shared memory 和 atomics。
- N-API 已經添加,Native 模塊開發更加方便。
- WHATWG-URL的實施得到了增強。
- 通過 util.promisify(),不需要再顯式創建 Promise 了。
LTS - Long Term Support
github: nodejs/LTS
LTS介紹
偶數版本會在每年四月發布,然後在10月份開始長期支持。
LTS 會一直支持18個月,然後將進入長達一年的維護期。
這兩種方式的區別主要是修復的優先順序。- Bug修復
- 安全更新
- 文檔更新
- 無破壞性的功能更新
發布計劃
版本表格
V8
V5.7主要更新
- promise 和 async 提速
- spread operator, destructuring 和 generators 提速
- 通過 TurboFan, RegExp 提速了 15%
- padStart 和 padEnd 被添加到了 es2017 (ECMA 262)
- Intl.DateTimeFormat.prototype.formatToParts 被添加到了 (ECMA402)
- WebAssembly 默認打開
- 添加 PromiseHook
v8-release-57
speeding-up-v8-regular-expressionsV5.8主要更新
- 任意設置堆大小的限制值 (範圍是帶符號32位整數)
- 啟動性能提升約5%
- 縮短 IC 系統的代碼編譯,分析,優化時間
v8-release-58
one-small-step-for-chrome-one-gianthow-v8-measures-real-world-performanceES2017 在 (v5.7, v5.8) 中的狀況
Object static methods: values, entries, getOwnPropertyDescriptors
Table: node.green, compat-table
Slide: abouthiroppy/ecmascriptES2017(MISC, ANNEX B), ES2018
- ES2017
- misc
- node.green/#ES2017-misc
- annex b
- Object.prototype getter/setter methods
- Proxy internal calls, getter/setter methods
- assignments allowed in for-in head in non-strict mode
- misc
- ES2018
- template literal revision
- v5.9 With flag
- template literal revision
TURBOFAN + IGNITION
V8: Behind the Scenes (November Edition feat. Ignition+TurboFan and ES2015)
TURBOFAN 編譯器
V8 優化了 JIT 編譯器,它是用 Sea of Nodes 概念進行設計的。之前採用的編譯技術是 Crankshaft,它支持優化更多的代碼。但是 ES 的標準發展很快,後來發現 Crankshaft 已經很難去優化 ES2015 代碼了,而通過 Ignition 和 TurboFan 可以做到。
TurboFan
High-performance ES2015 and beyondIGNITION 解釋器
已知的是到目前為止 V8 都沒有自己的解析器,都是直接把 JS 編譯成機器碼。
作為JIT的JIT的問題,即使代碼被執行一次,它也消耗大量的存儲空間,所以需要盡量避免內存開銷。使用 Ignition,可以精簡 25% - 50% 的機器碼。
Ignition 是沒有依賴 Turbofan 的底層架構,它採用宏彙編指令。為每個操作碼生成一個位元組碼處理程序。通過 Ignition 可以較少系統內存使用情況。如圖:
Ignition Design Doc
Firing up the Ignition InterpreterNode.js 與 v8 底層探索8.0.0
變更了 8.0.0 的發布時間
原計劃是四月25號發布的,現在被延期到了5月30號。
V8版本從 v5.7 更新到 v5.8。這是為了兼容 ABI(Application Binary Interface)6.0。讓 V8 Ignition 和 TurboFan pipeline 進入 8.0.0,也方便 9.x backport 到 LTS。Ignition 和 TurboFan 在 v5.9 默認打開,到時候 Node 會以 semver-minor 方式升級到 v5.9。V8 plan for Node.js LTS Carbon (A potential path to TurboFan + Ignition)
Ignition + TurboFan: Node.js benchmarks計劃內容
- 04月21日: V8 v5.8 進入 stable
- 05月09日: semver-major 凍結
- 05月中旬: v6.0 API / ABI 進入 stable
- 05月30日: Node8 發布??
- 06月上旬: 如果 V8 v5.9 stable 則會被作為 semver-minor 進行更新
- 08月上旬: 更新到 V8 v6.0
版本說明
- semver-major: 8.0.0
- semver-minor: 7.x.0
- semver-patch: 7.x.y
8.0.0 Release Proposal
N-API
semver-minor since 7.8.0
nodejs/abi-stable-node什麼是 N-API(NODE-API)?
ABI stable abstraction layer of native module
不同的 Node 版本、VM間,提供 ABI (Application Binary Interface) 來保證兼容性,
支持 N-API 的本地模塊將無需重新編譯就可以工作。VM Summit - 2017-03-03
node-eps/005-ABI-Stable-Module-API.mdmodule: add support for abi stable module API問題點
目前 Node 的實現中,V8 的 API 是直接暴露出來的。由於 V8 經常變更 API,那就存在下面的這些問題:
- Native 模塊在每個版本間需要重新編譯
- Native 模塊需要變更代碼
- Native 模塊無法工作在其他JS engine 上 (比如: ChakraCore)
這些問題之前的 NAN(Native Abstractions for Node.js)(nodejs/nan) 搞不定。
N-API
目前已經在 ChakraCore 中驗證了
abi-stable-node/tree/doc
已經進行 N-API 適配的模塊
ASSERT
默認支持 map, set
semver-major
> assert.deepEqual(new Set([1, 2]), new Set([1]))AssertionError: Set { 1, 2 } deepEqual Set { 1 } at repl:1:8 at ContextifyScript.Script.runInThisContext (vm.js:44:33) at REPLServer.defaultEval (repl.js:239:29) at bound (domain.js:301:14) at REPLServer.runBound [as eval] (domain.js:314:12) at REPLServer.onLine (repl.js:433:10) at emitOne (events.js:120:20) at REPLServer.emit (events.js:210:7) at REPLServer.Interface._onLine (readline.js:262:10) at REPLServer.Interface._line (readline.js:611:8)> assert.deepEqual(new Set([1, 2]), new Set([1, 2]))undefined
nodejs/node#12142
BUFFER
添加 icu.transcode()
semver-minor since 7.1.0
通過使用 icu transcode,把 Node 支持的編碼從緩衝區轉移到另一個緩衝區。
> const icu = process.binding("icu");undefined> const newBuf = icu.transcode(Buffer.from("€"), "utf8", "ascii"); // source, from, toundefined> console.log(newBuf)<Buffer 3f>> Buffer.isBuffer(newBuf)true
buffer: add buffer.transcode
CHILD_PROCESS
添加 channel 到公共介面
semver-minor since 7.1.0
之前是名為 _channel 的私有介面,這個私有介面將來會被廢棄掉。
IPC(Inter Process Communication) 會返回一個到 channel 的引用。> const fork = require("child_process").fork> const n = fork("./test.js")> n.channelPipe { bytesRead: 0, _externalStream: [External], fd: 12, writeQueueSize: 0, buffering: false, onread: [Function], sockets: { got: {}, send: {} } }> n.channel === n._channeltrue
child_process: add public API for IPC channel
CLUSTER
worker.disconnect() 返回引用
semver-minor since 7.3.0
if (cluster.isMaster) { const worker = cluster.fork(); cluster.fork().on("listening", (address) => { setTimeout(() => { const w = worker.disconnect(); console.log(w); // undefined // Worker // 7.3.0 ~ }, 1000); }); cluster.on("exit", (worker, code, signal) => { console.log(`worker ${worker.process.pid} died`); });} else { http.createServer((req, res) => {}).listen(8000);}
cluster: return worker reference from disconnect()
CRYPTO
setAuthTag 和 setAAD 返回 this 對象
semver-minor since 7.2.0
> const key = "0123456789"> const tagbuf = Buffer.from("tagbuf")> const aadbuf = Buffer.from("aadbuf")> const decipher = crypto.createDecipher("aes-256-gcm", key)> decipher.setAuthTag(tagbuf)Decipher { _handle: {}, _decoder: null, _options: undefined, writable: true, readable: true }> assert.strictEqual(decipher.setAuthTag(tagbuf), decipher)undefined> assert.strictEqual(decipher.setAAD(aadbuf), decipher)undefined
crypto: return this in setAuthTag/setAAD
支持系統 CA
semver-minor since 7.5.0
支持能夠使用系統提供 CA。
CLI: --use-openssl-ca, --use-bundled-ca環境變數: SSL_CERT_DIR=dir, SSL_CERT_FILE=filecrypto: use system CAs instead of bundled ones
DNS
TTL 變成可用
semver-minor since 7.2.0
可以通過 dns.resolve4() 、 dns.resolve6() 獲取每個記錄的TTL(生存時間)。
> dns.resolve4("google.com", {ttl:true}, console.log)null [ { address: "216.58.221.174", ttl: 273 } ]> dns.resolve6("google.com", {ttl:true}, console.log)null [ { address: "2404:6800:400a:807::200e", ttl: 242 } ]
dns: implement {ttl: true} for dns.resolve4() and dns.resolve6()
FS
支持 File 協議
semver-minor since 7.6.0
在 fs 模塊中支持使用 whatwg-url 的文件協議。
根據 whatwg-url 的 spec,必須使用文件的絕對路徑。> const URL = require("url").URL;undefined> const myURL = new URL("file:///C:/path/to/file");undefined> fs.readFile(myURL, (err, data) => {});TypeError: path must be a string or Buffer// 7.6.0 ~> fs.readFile(myURL, (err, data) => {});undefined
fs: allow WHATWG URL and file: URLs as paths
fs.SyncWriteStream 已經廢棄
semver-major
> fs.SyncWriteStream...> (node:57352) [DEP0061] DeprecationWarning: fs.SyncWriteStream is deprecated.
nodejs/node#10467
HTTP/HTTPS
添加 OutgoingMessage
semver-minor since 7.7.0
添加了三個方法:
getHeaderNames(), getHeaders(), hasHeader()
無需再調用 _headers 私有對象
const http = require("http");http.createServer((req, res) => { res.setHeader("x-test-header", "testing"); res.setHeader("X-TEST-HEADER2", "testing"); console.log(res._headers); // { "x-test-header": "testing", "x-test-header2": "testing" } console.log(res.getHeaders()); // { "x-test-header": "testing", "x-test-header2": "testing" } console.log(res.getHeaderNames()); // [ "x-test-header", "x-test-header2" ] console.log(res.hasHeader("X-TEST-HEADER2")); // true}).listen(3000, function() { http.get({ port: this.address().port }, (res) => {});});
http: add new functions to OutgoingMessage
在 request 中使用 URL
semver-minor since 7.5.0
http.request 和 https.request 可以使用 URL 對象。
const http = require("http");const url = require("url");const URL = url.URL;const server = http.createServer((req, res) => { console.log(req.url); // /foo?bar console.log(req.method); // GET res.end(); server.close();}).listen(3000, function() { const u = `http://localhost:${this.address().port}/foo?bar`; http.get(u); http.get(url.parse(u)); http.get(new URL(u)); // 7.5.0 ~});
url: allow use of URL with http.request and https.request
INSPECTOR
添加 --inspect-brk
semver-minor since 7.6.0
--debug-brk 通過這個參數,在開始調試的時候能夠定位到代碼的第一行。
$ node --inspect-brk test.jsDebugger listening on 127.0.0.1:9229.To start debugging, open the following URL in Chrome: chrome-devtools://devtools/bundled/inspector.html?experiments=true&v8only=true&ws=127.0.0.1:9229 ...Debugger attached.
inspector: add --inspect-brk flag
V8 inspector 的切換
semver-major
Node 8 之後 --debug 就不再支持了。
$ node --debugnode: bad option: --debug$ node --inspectDebugger listening on 127.0.0.1:9229.To start debugging, open the following URL in Chrome: chrome-devtools://devtools/bundled/inspector.html?experiments=true&v8only=true&ws=127.0.0.1:9229 ...>$ node --inspect-brkDebugger listening on 127.0.0.1:9229.To start debugging, open the following URL in Chrome: chrome-devtools://devtools/bundled/inspector.html?experiments=true&v8only=true&ws=127.0.0.1:9229 ...
Switch the CLI debugger to V8 inspector
deps: Add node-inspectsrc: Remove support for --debug添加 --
semver-minor since 7.5.0
-- 在 -e 之後說明是 end-of-options
$ node -e "console.log(process.argv)" -- -arg1 -arg2[ "/Users/xxx/.yyy/node/v7.4.0/bin/node" ]# 7.5.0 ~$ node -e "console.log(process.argv)" -- -arg1 -arg2[ "/Users/xxx/.yyy/node/v7.5.0/bin/node", "-arg1", "-arg2" ]
-- after -e <script> means end-of-options
PROCESS
添加 NODE_NO_WARNINGS
semver-minor since 7.5.0
通過設置 NODE_PRESERVE_SYMLINKS 環境變數為 1 關閉進程的 warning 信息。
參數 --no-warnings 效果同上。process: add NODE_NO_WARNINGS environment variable
添加 NODE_PRESERVE_SYMLINKS
semver-minor since 7.1.0
通過設置 NODE_PRESERVE_SYMLINKS 環境變數為 1 開啟符號鏈接。
參數 --preserve-symlinks 效果同上。Add NODE_PRESERVE_SYMLINKS environment variable
添加 externalMemory
semver-minor since 7.2.0
返回 C++ 對象的內存使用量。
> console.log(util.inspect(process.memoryUsage()));{ rss: 23371776, heapTotal: 10465280, heapUsed: 5756560 }// 7.2.0 ~> console.log(util.inspect(process.memoryUsage()));{ rss: 23244800, heapTotal: 7692288, heapUsed: 4918392, external: 22846 }
process: add externalMemory to process.memoryUsage
PROMISE
堆棧的優化
通過參數 --trace-warnings 開啟優化 Promise 和 UnhandledPromiseRejectionWarning 堆棧信息。
$ node --trace-warnings> const p = Promise.reject(new Error("This was rejected"))> setImmediate(() => p.catch(() => {}))(node:40981) Error: This was rejected...(node:40981) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated.In the future, promise rejections that are not handled will terminatethe Node.js process with a non-zero exit code....(node:40981) PromiseRejectionHandledWarning:Promise rejection was handled asynchronously (rejection id: 1) at getAsynchronousRejectionWarningObject (internal/process/promises.js:12:10) at rejectionHandled (internal/process/promises.js:42:21) ...
promise: better stack traces for --trace-warnings
URL
WHATWG-URL
NODE-WHATWG-URL
UTIL
添加 [Array] 的符號
semver-major
對於嵌套數組,改為寫為[Array]。
> const obj = util.inspect({"a": {"b": ["c"]}}, false, 1)> obj"{ a: { b: [Object] } }"> assert.strictEqual(obj, "{ a: { b: [Array] } }")AssertionError: "{ a: { b: [Object] } }" === "{ a: { b: [Array] } }"// 8.0.0> obj"{ a: { b: [Array] } }"> assert.strictEqual(obj, "{ a: { b: [Array] } }")undefined
nodejs/node#12046
添加新的 format
semver-minor since 7.9.0
- %i: 格式化為整型
- %f: 格式化為浮點型
> util.format("%d", 42.2)"42.2"> util.format("%i", 42.2)"%i 42.2"> util.format("%f", 42.2)"%f 42.2"// 8.0.0> util.format("%d", 42.2)"42.2"> util.format("%i", 42.2)"42"> util.format("%f", 42.2)"42.2"
util: add %i and %f formatting specifiers
從 util.format 中刪除 SIMD
semver-major
這是因為 V8 已經不支持 SIMD 了。
$ node --harmony_simd> assert.strictEqual(util.inspect(SIMD.Int32x4()), "Int32x4 [ 0, 0, 0, 0 ]");undefined// 8.0.0> assert.strictEqual(util.inspect(SIMD.Int32x4()), "Int32x4 [ 0, 0, 0, 0 ]");AssertionError: "Int32x4 {}" === "Int32x4 [ 0, 0, 0, 0 ]"
lib: remove simd support from util.format()
url.format 支持 WHATWG-URL
semver-minor since 7.6.0
> const URL = require("url").URL> const myURL = new URL("http://example.org/?a=b#c")> const str = url.format(myURL, {fragment: false, search: false})> console.log(str)http://example.org/?a=b#c// 7.6.0 ~> console.log(str)http://example.org/
url: extend url.format to support WHATWG URL
v8對象
添加 does_zap_garbage
semver-minor since 7.2.0
v8 HeapStatistics 已經添加 does_zap_garbage。
這是一種覆蓋堆垃圾的模式。通過參數--zap_code_space 開啟。malloced_memory, peak_malloced_memory 同時被添加到欄位中。> v8.getHeapStatistics(){ total_heap_size: 7168000, total_heap_size_executable: 3670016, total_physical_size: 6132432, total_available_size: 1492201768, used_heap_size: 5416688, heap_size_limit: 1501560832, malloced_memory: 8192, peak_malloced_memory: 1412016, does_zap_garbage: 0 }
src: Add does_zap_garbage to v8 HeapStatistics
正在進行中的任務
遷移 errors 到 internal/errors.js
semver-major
在當前 Node 的核心模塊中,每個文件中都會定義錯誤信息。現在的任務是統一到internal/errors.js
/lib/internal/errors.js
Tracking Issue: Migrate errors to internal/errors.js
支持 Uint8Array
- open: stream: support Uint8Array input to methods
- open: string_decoder: support Uint8Array input to methods
- closed: zlib: support Uint8Array in convenience methods
- closed: dgram: support Uint8Array input to send()
- closed: tls: support Uint8Arrays for protocol list buffers
- closed: crypto: support Uint8Array prime in createDH
- closed: child_process: support Uint8Array input to methods
- closed: fs: support Uint8Array input to methods
- closed: buffer: allow Uint8Array input to methods
添加 promisify()
semver-minor since ???
這可以說是最令人興奮的 PR 了。通過 util.promisify,原生模塊完美支持 async/await
const util = require("util");const setTimeoutPromise = util.promisify(setTimeout);setTimeoutPromise(2000, "foobar").then((value) => console.log(value));const stat = util.promisify(require("fs").stat);async function callStat() { const stats = await stat("."); console.log(`This directory is owned by ${stats.uid}`);}callStat();
util: add util.promisify()
推薦閱讀:
※從零開始寫一個 Node.js 的 MongoDB 驅動庫
※nodejs + react + redux 實踐
※在Egg中使用GraphQL
※Node.js 性能調優之內存篇(二)——heapdump
※NodeJS 工程師必備的 8 個工具
TAG:Nodejs |