2018年のNodeのトピックス

古川陽介氏:よろしくお願いします。

(会場拍手)

僕、実は元DeNAなんですよね。「こんな大きなイベント開けたっけな?」ってちょっと今(笑)。「『Node学園祭』の時もっと渋かった気がしたんだけどな」って思っているですが、いろいろ華やかな感じになって、DeNA生まれ変わっていいですね。

実は明日「Node学園祭」という大きなイベントを抱えていて、本当はこんなことしてる場合じゃないんですよ(笑)。明日の準備をしなきゃいけないんですね。8時から集合なんですよ。なので、10分後には行くんですけど。

僕は「yosuke_furukawa」と申します。Node.jsのJapan Node.js Associationの代表理事をやっています。「Node.js 2018」ということで、v10とかv11の話とかをしようと思います。

Node.jsの最近のトピックとしてはv11がリリースされました。すごいいろんな機能はあるんですが、v11自身は実はあんまり大した機能はないんですよね。どちらかというと、v11の紹介するよりは、v10で今まで入っていたものを紹介しながらv11でなにがあったかを紹介したほうが流れが説明しやすいので、紹介していこうと思っています。

Node.js v10.0.0からv10.13.0……までやってるのかな? 10.12.0まで出てるところがあるんですが、そこでいろいろ入っていて。例えば、HTTP/2の “experimental” flagが外れていたりとか、ES Modulesが入っていたりとか、あとError Codeでコードでエラーハンドリングできたりとか。

あと、ファイルシステムをいじるfsというAPIにpromisesが追加されたり、Streamが改善されたり、Workerが追加されたり、いろいろやっているんですね。

v11なにがあったかというと、あまり目立ったものはなくて。1つは、V8 version 7対応されて、WebAssemblyと呼ばれている技術が改善されたというものだったり。

あと、Node.jsで使っている人がいるかどうかはわかりませんが、「require('url')」ってurl moduleというのが使えるんですけど、そのurl moduleをrequireするのはdeprecatedになりました。そのかわりglobalに、global.urlというのが生えているので、それを使えということになりましたね。

あと、TextEncoder・TextDecoderというのもglobalになりました。queueMicrotask APIが実験的に追加されました。

このへんのたぶんコアな話は、みなさんあまり興味がないんじゃないかと思っていますが、どうですかね? 「それよりChrome Dev Summitの話をしたほうが楽しいかもしれないな」とも思ったんですけど、ここままいっていいですか? いいか、このままいきます。

v10とHTTP/2について

まずなにが追加されたかというと、v10で追加されたHTTP/2の話をちょっとしようかなと思います。そもそも今みなさんが普通に使われているプロトコルだとHTTP/1.1なのかもしれないですが、最近はHTTP/2のサイトが増えているので、もはやこのあたりの問題を言ったところで、もうあまり起きていない問題の1つなんですけど。

昔はブラウザからサーバに対してリクエストを投げるときに、6つまでしかリクエストできないという制限がありました。それはブラウザで決めている制約で、Node.js自身は実は何本もコレクションを張ればリクエストを多重化できます。

そうすると、ブラウザにせよ、Node.jsにせよ、1本遅いリクエストがあっただけで、それを待たなければいけません。次にまたもう1個貼るとき、もしその1個のリクエストが遅いままだと、次からは5つしかリクエストを投げられないという状況が続きます。

これが「Head of Line Blocking」と呼ばれていた、HTTP/1.1までにあった問題ですね。ATMの前で1人が遅い処理をしていると、そのタイミングでみんなの処理が待たされますよね。それと一緒で、Head of Line Blockingというのは、1人遅い人がいると、それがずっと続いてしますという感じです。

HTTP/2はそのHead of Line BlockingをHTTP/2のプロトコルのレベルで解決しているということで。実はコネクションを張っているのは1本しかないんですよね。TCPのコネクションは1本しか張ってなくて、その中で多重化するという技術を使って、HTTP/2は、Head of Line Blockingが起きたとしても、ほかのリクエストを多重化して送れるようになりました。

これがNode.jsに入りました。GopherくんをつかってNode.jsでデモしたときに、意図的にHead of Line Blockingを起こすような画像を使ってファイルをロードさせると、HTTP/1.1のときはだいたい17秒かかっていたのが、HTTP/2だと2秒ぐらいになる。

HTTP/2にはさらにいろんな改善が追加されていて、Server PushとかPriority Hintsとか、HTTPのさらに拡張された技術があるんですが、そういった技術を使うとさらに早くなります。2秒から1.7秒くらいにはなるという感じで、徐々にこうやって改善されていっております。

新たに追加された機能たち

2つ目が、BabelとかRollupとか使っていると、ES Modulesって構文でimport / exportっていう構文が使えてますよね。これをNode.jsでも使えるようになりました。

ただ、一応「.mjs」という拡張子じゃなきゃいけなかったり、experimental flagを入れなきゃいけなかったり等々で、制約はあるですが使えるという状況ですね。

さらに、もっといろんな機能が追加されていて、Workerとか。なんでこれが入ったかというと、Workerというか、そもそもNode.jsの最近のユースケースってだいたいこういうものばかりなんですよね。

Babelを使ってReactのJSXをtranspileしたり、webpack使ってバンドルしたり、Gulp・Gruntを使ってタスクマネジメントしたりとか、こういう処理って全部CPUのヘビーなタスクなんです。

考えてみればわかります。ファイルを取ってきて、ファイルをなにかしらのファイルに置き換えて、それをtranspileして、それをガッチャンコさせて1つのファイルにする処理って、全部文字列連結と文字列変換の塊なので、CPUタスクなんですよね。

これを高速化するにはマルチスレッドするしかありません。要は複数のCPUをいっぺんに走らせて並列に処理させるしかありません。それを実現するのがWorkerです。

例えば、マスターとなる1つのプロセスが、Workerである子スレッドに対して、「この処理をしてくれ」というふうに並列処理をさせます。

例えば「Babelでtranspileする」といったシチュエーションだと、ターゲットファイルが100個とか1,000個あって、その100個、1,000個をすべてほかのスレッドに任せて実行させて、「終わったら教えて」というかたちで、別なコアを並列に、Gulpを使ってtranspileかけます。

今だとNode.jsは1つのプロセスしか使っていないはずなので、コアが例えば4個あると、ほかの3つは遊んでいる状態です。でも、Workerを使ってほかの4並列で動かせば、4つ全部使って動かすので、そのほうが速いです。

WorkerはこのThreadを使えるようにするためのものです。Node.jsでmulti threadプログラミングができる。まぁ、うれしいかどうかわからないですけど(笑)、ついにできます。

これをやると、結果としてはシングルスレッドでBabelを動かすのと、マルチプロセスで動かすのと、マルチスレッドで動かすのをそれぞれ比較すると、シングルスレッドよりもマルチスレッドで動かすほうが速くなっているという感じですね。こんな感じでNode.jsは徐々に早くなっております。

あんまり時間がないので、次。「Stream/Promiseの親和性改善」とかいろいろあるんですけど、このへんちょっと飛ばしますね。なぜかというと、これは「HTML5 Conference」で話すからです(笑)。

(会場笑)

そこでもうちょっと詳しくしゃべります。

まぁ全部飛ばしちゃうとあれなんですが、Node.jsって非同期処理のやり方が複数あるんです。1つはCallback。もう1つはStream。EventEmitterというかたちでイベントで処理します。

さらに最近、ECMAScriptではPromiseと呼ばれている処理が入っています。この3つがあるので、「どれを使うの?」という状態になっています。たぶんみなさんもそうなっていると思うんですけど。

そんな状態をなんとか改善するために、StreamとPromiseをうまく融合させようという取り組みが、このStream PipelineとStream Finishedというものです。

さらにPromiseを使うときには、Node.jsのPromiseを使うときもいくつか改善されています。このへんは難しい話なのですっ飛ばしますね。

Node.js v12について

「Node.js v12からどうするか?」というところで、v11・v10まではどちらかというと、HTTP/2が入ったりWorkerが入ったり、ES Modulesが入ったりと、その他もろもろ入っていて、かなり新しい進化をしてはいるんですけど、その進化って何の進化なのかというと……。

2016年に、JamesさんというNode.jsのコアメンバーの1人が来て話していたんですが、Node.jsは、今はWebアプリケーション開発のためのプラットフォームであると。主な使われ方としてはそれであると。

ただ、Node.jsは「small core」と呼んでいるんですが、そんなにたくさん機能を入れないようにして、コア自身をsmallにした上で、パフォーマンスや安定性をモチベーションとして持ってやっていると。

それが哲学なんだけれども、彼が言うには、「Webアプリケーション開発においては、コアのAPIは、WHATWGとかW3CとかTC39とかIETFみたいなWeb Standardを作っている人たち寄り添うべきだ」というふうに言っているんですね。

これが「critical internet standards」と言っているんですけど、このinternet standardのやっていることに寄せていくべきだろうって言っています。

今ホットトピックとしては、やはりWeb Standard APIとの親和性向上なんですよね。これ自身は、Open Standard Projectというかたちで、Node.jsの1つのカテゴリとして今は活動しています。

今なんとなくできているAPIとしては、例えばConsole。「console.log……」ってNode.jsで書くと普通に動くと思うんですけど、あれは一応WHATWGでConsole APIとして提供されているものをうまく活用したかたちで使われています。あとTextEncoder・DecoderというAPIとか。あとURLもそうですね。

それも全部ブラウザに新しく生えたURLとかAPIとかに寄り添うかたちで、Web Standardに寄り添うかたちで進化していっています。

今後想定されるものとしては、fetchとかWHATWG Streamとか、そういうものをやっていこうという話が出てきています。ただ、どこまで本気でやるかは、それこそNode学園祭に来ていただかないとわからないですね。

(会場笑)

Node学園祭の中で、これを提案している人たちが来るので、そこで実際に聞いてみようかなと思っておりますというところですね。

というのわけで、この先は11月25日の「HTML5 Conference」でもっと詳しくしゃべろうかなと思うので、今回はここらへんで終わろうかなと思います。ありがとうございました。

(会場拍手)