標籤:

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-expressions

V5.8主要更新

  • 任意設置堆大小的限制值 (範圍是帶符號32位整數)
  • 啟動性能提升約5%
  • 縮短 IC 系統的代碼編譯,分析,優化時間

v8-release-58

one-small-step-for-chrome-one-giant

how-v8-measures-real-world-performance

ES2017 在 (v5.7, v5.8) 中的狀況

Object static methods: values, entries, getOwnPropertyDescriptors

Table: node.green, compat-table

Slide: abouthiroppy/ecmascript

ES2017(MISC, ANNEX B), ES2018

  1. 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
  2. ES2018
    • template literal revision
      • v5.9 With flag

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 beyond

IGNITION 解釋器

已知的是到目前為止 V8 都沒有自己的解析器,都是直接把 JS 編譯成機器碼。

作為JIT的JIT的問題,即使代碼被執行一次,它也消耗大量的存儲空間,所以需要盡量避免內存開銷。

使用 Ignition,可以精簡 25% - 50% 的機器碼。

Ignition 是沒有依賴 Turbofan 的底層架構,它採用宏彙編指令。為每個操作碼生成一個位元組碼處理程序。

通過 Ignition 可以較少系統內存使用情況。

如圖:

Ignition Design Doc

Firing up the Ignition Interpreter

Node.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

計劃內容

  1. 04月21日: V8 v5.8 進入 stable
  2. 05月09日: semver-major 凍結
  3. 05月中旬: v6.0 API / ABI 進入 stable
  4. 05月30日: Node8 發布??
  5. 06月上旬: 如果 V8 v5.9 stable 則會被作為 semver-minor 進行更新
  6. 08月上旬: 更新到 V8 v6.0

版本說明

  1. semver-major: 8.0.0
  2. semver-minor: 7.x.0
  3. 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.md

module: 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=file

crypto: 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-inspect

src: 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

  1. open: stream: support Uint8Array input to methods
  2. open: string_decoder: support Uint8Array input to methods
  3. closed: zlib: support Uint8Array in convenience methods
  4. closed: dgram: support Uint8Array input to send()
  5. closed: tls: support Uint8Arrays for protocol list buffers
  6. closed: crypto: support Uint8Array prime in createDH
  7. closed: child_process: support Uint8Array input to methods
  8. closed: fs: support Uint8Array input to methods
  9. 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 |