読者です 読者をやめる 読者になる 読者になる

Node.js v5.0 がリリースされました。

Node.js v5.0 がリリースされました!!

今回はどちらかと言うと機能面というより、 Node.js v5.0 の位置づけを中心に解説したいと思います。

機能面も一応載せますが、学園祭前で時間があまり作れないので、さくっと終わらせます。

機能面での変更

ES2015の文法追加

Spread operator が追加

Spread operator が追加されました。

これまで配列をJavaScriptの関数に引数に展開して渡す場合、以下のように記述する必要がありました。

function f(x, y, z) {
  console.log(x);
  console.log(y);
  console.log(z);
}
var args = [0, 1, 2];
f.apply(null, args);

この書き方はあまり直感的じゃなく、また new 演算子と併用できないという問題があったりします。

Spread operator によって Node.js v5.0 からは以下のように記述することができます。

function f(x, y, z) { 
  console.log(x);
  console.log(y);
  console.log(z);
}
var args = [0, 1, 2];
f(...args);
new.target の追加

new.target というのはメタプロパティの一つです。 new 演算子で呼ばれた場合にnew.targetに実行しているオブジェクトのプロパティがbindされます。
これを使うことで、例えばnew で指定されたクラス名をコンストラクタ内から参照することや new 演算子をうっかり付けずにinvokeされたコンストラクト関数をエラーにすることといった事が可能です。

function Foo() {
  // new を付けて呼ばれなかったらエラーにする
  if (!new.target) throw "Fooを呼び出す際はnew演算子を必ず付けてください";
  console.log(new.target.name);
}

Foo(); //エラー: Fooを呼び出す際はnew演算子を必ず付けてください
new Foo(); // Foo

また class の継承などと併用すると以下のようにnew した対象のクラスがコンストラクタから取得できるようになります。

'use strict';
class A {
  constructor() {
    console.log(new.target.name);
  }
}

class B extends A { constructor() { super(); } }

var a = new A(); // "A"
var b = new B(); // "B"

npm v3

Node.js のパッケージマネージャである npm が v2 からv3 にアップグレードされました。

npm v3 に関しての詳細は @watilde さんの資料が詳しいです。


一応概要を説明しておくと

  • 階層を極力 flat に保つようになった
  • エラー文言などがより親切に
  • progress barがちゃんと出るようになった

という幾つかのアップデートがあります。とくにflat階層になったのが大きく、flat化される事によってパスが260文字までしか入らない制約を持つ、Windowsフレンドリーなパッケージマネージャになっています。

ALPN サポート

大津さんが ALPN をサポートしてくれました。ALPNとは、 Application layer protocol negotiation の略で、クライアント・サーバ間でプロトコルを利用する際にどのプロトコルを使えるのかを交渉するための処理のことを指します。

これまでは NPN といって、クライアントがサーバーに使えるものを問い合わせて、サーバーが利用可能なプロトコルの一覧をクライアントに返し、そこからクライアントがプロトコルを選ぶ、というやり方しかNode.jsはサポートしていませんでした。

あすのかぜブログにわかりやすい図があったので引用します。

TLS上でのプロトコルネゴシエーションの仕組み、NPNとALPN - あすのかぜ

NPNの図

http://cdn-ak.f.st-hatena.com/images/fotolife/A/ASnoKaze/20130207/20130207233639.png


ALPNでは、クライアントがサーバーに対して最初の交渉の時点で自分が使えるものを渡すことができるようになります。決定権をサーバーが持つようになるといった部分がこれまでとは異なります。

http://cdn-ak.f.st-hatena.com/images/fotolife/A/ASnoKaze/20130208/20130208001012.png


ALPNがサポートされたことでユーザーランドでhttp2やspdy/3を作っているライブラリがALPNを使ってプロトコルを交渉する事ができるようになりました。
tlsでサーバーを作る時に ALPNProtocols オプションを使って指定します。

var tls = require('tls');
var fs = require('fs');

var options = {
  key: fs.readFileSync('server.pem'),
  cert: fs.readFileSync('server.crt'),
  passphrase: 'test',
  rejectUnauthorized: false,
  // ここで指定可能なALPNプロトコルを指定する
  ALPNProtocols: ['http/2', 'spdy/3.1'] 
};

var server = tls.createServer(options, function(socket) {
  // http/2
  console.log(socket.alpnProtocol);
});
server.listen(8000, function() {
  console.log('server bound');
  var client = tls.connect(8000, 'localhost', {
    // Client側からServer側に交渉
    ALPNProtocols: ['http/2'],
    rejectUnauthorized: false
  }, function(){
    // 交渉が成立するとココで http/2 になる
    // 交渉不成立だと false になる
    console.log(client.alpnProtocol);
  }); 
});

そのほか変更点

console.timeがミリ秒よりも細かい精度に対応

github.com

console.time('100-elements');
for (var i = 0; i < 100; i++) {
  ;
}
console.timeEnd('100-elements');
// 100-elements: 225.438ms
// 今までは225msまでしか出なかった(内部でDate.nowを使っていたため)。

deprecated / removed

これまで長らくdeprecatedだった機能がこのメジャーバージョンアップを機会に消えたり、新たにdeprecatedになった機能が増えたりしています。

github.com
github.com
github.com
github.com


使っていたところでエラーが出るような機能だったり、deprecatedになってもう何年もたつような物が対象なので消えても困るような人は少ないと思いますが、一応注意してください。

バージョンについて

今回 Node.js v5.0 (Stable) というラベルがついています。 Stable というラベルが付いていますが、以前のNode.jsのバージョンは Node.js v4.0 (LTS Argon) という風に LTS ラベルとArgonという名前がついています。

Stable と LTS の違い

さて、ここが今回の話の目玉です。

v0.12までのNode.jsは奇数の開発バージョン(v0.11)、偶数の安定バージョンがあり(v0.12, v0.10)、偶数の安定バージョンを最新を含む2バージョンまでサポートするという形式をとっていました(v0.12とv0.10のみサポート等)。これはセキュリティパッチや明らかなバグがあれば下位バージョンであるv0.10にback portして提供することを意味しています。

逆に言うと、新しい偶数の安定バージョンが出た(v0.14)場合、古い安定バージョン(v0.10)はその時点でサポートされなくなります。これが今までのNode.jsの中で痛みを伴う部分でした。リリーススケジュールが明確じゃないのでNode.jsの新しいバージョンが出るタイミングがわからず、Node.jsのアップグレードする人は常に頭を悩ませるような状態でした。

今回、Long Term Support(LTS)の仕組みができました。これは長期サポートといって、リリースしてから2年半は確実にメンテナンスを行うというサポートポリシーです。これによって、アップグレードは必ず2年半単位で実施する必要ができています。サポートポリシーができたことによって開発者がアップグレード計画を立てやすくなるという効果を狙っています。

https://github.com/nodejs/LTS/raw/master/schedule.png


このLTSにはバージョンとは違ってLTSであることを表すための識別名が付きます、それがArgonです。識別名は元素名なので、次は Boron とか次の次は Carbon なんじゃないかと推測できます。

ただ全てのバージョンをLTSとして扱うとサポートする側が大変になるのでやりません。基本的に3つまでしかLTSとなるバージョンは存在しません。今で言えば、v0.10, v0.12, v4.x です。

f:id:yosuke_furukawa:20151105173736p:plain

次に出るLTSがv6なのかは実は決まっていません。よく偶数バージョンがLTSで奇数バージョンがStableという書かれ方をしている記事を見ますが、そのルールがこれからもずっと継続するのかは個人的には疑問です

確実に決まっているのは、2016-10-01 で v0.10 のサポートが切れ、そのタイミングでリリースされるであろうバージョンが次のLTS対象になる、というのが正しい見解だと思っています。なので、上の表でも次のLTSにはバージョン番号の記述はされておらず、 v.Nextとしか書かれていません。

つまり、偶数バージョン = LTSではなく、 Argon, Boron などの LTS 識別名が付いているもの = LTS です。
バージョンはあくまでsemverにしたがって上がります。LTSとバージョン番号に直接の関係はあまりないと思ったほうが後々奇数バージョンでLTSが出た時に戸惑わずに済むんじゃないかと思っています。

Stableラベルであるv5.0は、LTSではないので、次のバージョンが出たらv5.0はメンテされません。今回のv5.0はホットに最新を追いたいようなエンジニアを対象としたバージョンになります。今すぐにアップグレードする必要はありませんが、次のLTSでサポートされるような機能をいち早く試したい場合はアップグレードをおすすめします。

LTSかどうかを識別する方法は?

先ほど Argon, Boron などのLTS識別名が付いているものという事を書きましたが、LTS識別名が付いているのかどうかを識別する方法は多少面倒です。
もしも nodebrew などのバージョンマネージャーを使っている場合はいずれ nodebrew install-binary lts とかで最新のLTSがダウンロードできるようにする予定です。

github.com

リリースされている一覧のJSONファイルが提供されているので、そこのLTSラベルをparseすることでバージョンマネージャは識別可能になると思っています。

目で確認する場合は、公式サイトのトップページに書いてある情報から識別するのが簡単だと思います。

まとめ

  • Node.js v5.0 が出ました。
  • Spread operator/new.target等のES2015の新機能が追加
  • npmがv2からv3に
  • ALPNが追加
  • LTS(v4) と Stable(v5) の違い

また、今度学園祭に来るRod Vaggがリリースを管理しているのでそこで聞いてみるのも良いかもしれませんね!(これが書きたかった)