別にしんどくないブログ

技術のことや読書メモを書いています

Node.js v13の主な変更点

Node.jsのv12がLTSになり、v13がcurrentとしてリリースされました。 ダウンロードは公式ページから行えます。

nodejs.org

今回はNode.js v13の主な変更点を紹介したいと思います。
以下リリースノートにあるNotable Changesからいくつかピックアップします。

nodejs.org

assert (PR: #28263)

assert.throws()またはassert.reject()でthrowされたエラーの検証にコンストラクターが使われた場合、throwされたエラーの代わりにAssertionErrorがスローされます。

コードで見た方がいいかもしれません。

// v12
const assert = require('assert');
const SomeError = class extends Error{};
try {
// 第一引数でthrowされたエラーがSomeErrorか判定
assert.throws(() => {throw new TypeError({})}, SomeError)
} catch (e) {
// eはTypeError
assert.ok(e instanceof TypeError)
}
view raw assert.throws.v12.js hosted with ❤ by GitHub
// v13
const assert = require('assert');
const SomeError = class extends Error{};
try {
// 第一引数でthrowされたエラーがSomeErrorか判定
() => assert.throws(() => {throw new TypeError({})}, SomeError)
} catch (e) {
// eはTypeErrorではなくAssertionErrorに内包されている
assert.strictEqual(
e,
{
generatedMessage: true,
actual: new TypeError({}),
expected: AssertionError,
code: 'ERR_ASSERTION',
name: 'AssertionError',
operator: 'throws',
message: 'The error is expected to be an instance of "AssertionError". ' +
'Received "TypeError"\n\nError message:\n\n[object Object]'
}
)
}
view raw assert.throws.v13.js hosted with ❤ by GitHub
gist.github.com

build (PR: #29887)

full-icuでビルドされるようになり、i18n系の機能ですべての言語をサポートしました。

Node.jsはこれまでビルド後のバイナリサイズの増加への懸念により、--with-intl=small-icuオプションを付けてビルドしていたバイナリを配布していました。
しかし、v13からは--with-intl=full-icuでビルドしたバイナリを配布するようになりました。
懸念されていたバイナリのサイズですが、macOSだと35MBから49MBになります。

オプションによる言語サポートの違いは以下の表のとおりです。こちらからも確認できます。

https://nodejs.org/api/intl.html#intl_options_for_building_node_js

挙動の違いに関するサンプルコードは以下のとおりです。

const january = new Date(9e8);
const spanish = new Intl.DateTimeFormat('es', { month: 'long' });
console.log(spanish.format(january))
// 'M01' v12
// 'enero` v13
view raw intl_v12_v13.js hosted with ❤ by GitHub
gist.github.com

v12以下(small-icuでビルドされたバージョン)はM01と出力しますが、v13以降(full-icuでビルドされたバージョン)はeneroと出力します。

console (PR: #29251)

console.timeEnd()console.timeLog()の結果がミリ秒ではなく時分秒の単位で出力するようになりました。

単位はh(時)、min(分)、s(秒)があります。

サンプルコードは以下の通りです。

const label = 'test';
console.time(label);
setTimeout(() => {
console.timeEnd(label);
}, 3000);
// 3001.732ms v12
// 3.001s v13
view raw console_timeEnd.js hosted with ❤ by GitHub
gist.github.com

v12では3001.732msと出力されていましたが、v13からは3.001sと出力されます。

deps (PR: #29694)

JavaScriptエンジンのV8のバージョンが7.8になりました。

これによりObjectの分割代入のパフォーマンス、メモリ使用量、WASMの起動時間が改善されます。
詳しくはV8のブログを読んでください。

v8.dev

http (PR: #29589)

古いHTTPパーサーが削除されました。

v12からすでにデフォルトではllhttpが使われています。

github.com

しかし、--http-parser=legacyとオプションをつけてnodeを起動すると古いパーサーを使うことも可能でした。
v13からはEnd-of-Lifeとなりました。オプション自体が削除されました。

llhttpはTypeScriptで書かれたhttpパーサーです。

github.com

古いHTTPパーサーは保守が難しく、またアーキテクチャ上パフォーマンスに問題がありました。
llhttpは保守性向上のためにTypeScriptで書かれています。それをCのコードやビットコードに変換しています。
古いHTTPパーサーに比べてパフォーマンスはかなり向上しています。

Image from Gyazo

http, http2 (PR: #27558)

デフォルトのサーバータイムアウト時間が変わりました。

これまでサーバーのタイムアウトの時間はデフォルト2分でした
リクエストが完了するまでに2分以上かかる場合、ソケットは閉じられ空のレスポンスを返していました。
そのため、画像の変換やサイズが大きいファイルのアップロードなど処理に時間がかかる場合、処理の途中でリクエストが閉じられることがありました。
これまでも--http-server-default-timeout=millisecondsオプションを使うことでユーザー側でもこの時間を変更することは可能でした。0に設定することでサーバータイムアウトを無効にすることもできました。

v13からはデフォルトで0が設定されるようになりました。つまりサーバータイムアウトが無効になりました。

最後に

今回紹介したのは一部の機能になります。自分が気になった変更をまとめただけですので、他にもすごい変更点はあるかもしれません。
また、ES Modulesもv13からフラグなしで使えるようになっていく予定になっています。

New Release Plan · Issue #400 · nodejs/modules · GitHub

PullRequestはもう出ていてマージされるとフラグ無しで使えるようになるので、興味のある方はウォッチすると良いかと思います。

github.com

Node.js v13は2020年6月でEnd-of-Lifeになる予定です。
次のNode.js v14は例年通りだと2020年4月にリリースされ10月末にLTSになる予定です。今回紹介したv13の機能も含まれます。

https://raw.githubusercontent.com/nodejs/Release/master/schedule.svg?sanitize=true

最後までお読みいただきありがとうございました。質問や不備はTwitterブコメなどでお願いいたします。