RxJS を学ぼう #1 - これからはじめる人のための導入編

React の登場と共に web フロントエンド界隈でも注目を集めるようになったリアクティブ・プログラミング ( RP ) 。その中でひときわ存在感を放っている1)オレ調べ。 RxJS について学んでみようと思います。

そもそも RxJS って何?

RxJS は Reactive Extensions for JavaScript の略称です。Observables というアーキテクチャを用いたリアクティブ・プログラミング用のライブラリであり、非同期処理 ( クリックなどイベント駆動の処理も含まれます ) を簡潔かつ可読性高くコーディング出来ることを主な目的としています。

で?Reactive Extensions ( Rx ) って何?

元々は Microsoft が C# 向けのライブラリとして設計・開発したものです。2009年に始動したプロジェクトから生まれたこの革新的なアーキテクチャはやがて様々な言語に移植されました。RxJS もそのうちの一つです2)他にも Java、Swift、Scala、C++、Ruby、Python、Groovy、JRuby、Kotlin などに移植されています。

よく関数型プログラミングと混同されがちですが、それは Functional Reactive Programing ( FRP ) と呼ばれるものであり、今回の題材である Rx とは別モノです。このあたりを語るとなるとそれだけで本が一冊書けてしまうほどのボリュームになるうえ、関数型界隈のおっかない有識者の方々からマサカリが飛んでくること請け合いなので、ここでは割愛します。以下のブログエントリがそのあたりについて非常に詳しく解説されているので、ご興味がある方は是非ご一読ください。

Angular や Cycle.js といったフレームワークの依存ライブラリとしても使われている

フルスタックフレームワークである Angular は幾つかの外部ライブラリに依存しており、そのうちの一つがこの RxJS です。例として http リクエスト周りにおいて内部で Observable を返すなどといった使われ方をしています。

Cycle.js は公式では xstream というライブラリに依存した使い方が推奨されていますが、代わりに RxJS を使うことも可能です。xstream は RxJS の軽量版といった位置づけで、API の数が少なく命名にも若干変更が入れられたライブラリです。jQuery に対する Zept のようなものだと思っていただければ OK です。

Cycle.js についてもいずれこのブログにてご紹介できればと思います。

このように RxJS はそれ単体での利用だけでなく、他ライブラリの機能を補う目的でも活用されているのが特徴です。

RxJS の三本柱 - Observables, Operators, Schedulers

RxJS の公式リポジトリにある README には次のように書かれています。

RxJS = Observables + Operators + Schedulers

Observables 非同期データソース ( ストリーム ) を表すクラスで、言葉通り Observe ( 観察 ) する何か
Operators Observable に対してフィルターをかけるなど値を加工するためのメソッド群
Schedulers 遅延操作をするなど Observables の並行性を制御するもの

Rx の基本は Observer パターン

Rx は Observer パターンを基本に据えています。その上でイベントや値 ( データ ) が時間軸という名のストリームを流れる要素として扱えるように設計されたものとなっています。

もう少し具体的な例を挙げてみます。『時間軸という名のストリーム』を一本の川に例えてみましょう。川にはいろいろなモノが流れています。Observable とは『』のことです。その川の上流からユーザーはボタンクリックやテキスト入力といったアクションによって『』を流します。流れる桃は一見するとどれも同じ見た目ですが、それぞれ中身が異なります。この桃こそが『イベント』であり、その中身こそがユーザーアクションによって送信された『』です。そして川に対して filter ( ある条件に一致する桃だけを下流に流す ) や merge ( 複数の川を合流させて一本の川にする ) といった操作を Operators と呼びます。

Schedulers は川の流れを遅らせたりするといったものですが、Observables や Operators ほど利用頻度は高くありません。より高度な使い方をするときに改めて学べは良いでしょう。

と、ここまで話が抽象的すぎて何のことだかサッパリかもしれませんが、はじめのうちは「川!?桃!?そういうのもあるのか!?」といった程度に読み進めていただいて構いません。自分でコードを書き進めていけばそのうち自然と理解できますので、今は騙されたと思ってスルーしてくださいませ。

はじめての RxJS を書いてみよう

長々とした能書きはこれくらいにして、そろそろ実際にコードを書いてみるとします。

TypeScript のすゝめ

サンプルコードは全て TypeScript で記述します。というのも Observables は非同期に値が流れてくるという特性から、どういった値が来るのかが予め明確になっていないと後々で流れの追いにくいコードになりやすいため、少しでも値に関する情報を明確にするために型を指定できる TypeScript が適しているのです3)僕は試していませんが、もちろん FlowType でも同様の恩恵を受けられると思います。

クリックイベント処理を RxJS を使って書いてみる

まずは RxJS を使わない普通の書き方です。

const button = document.querySelector('button');
button.addEventListener('click', (event: MouseEvent) => {
    console.log(`${(event.target as HTMLButtonElement).textContent} is clicked!!`);
});

なんてことはない、ボタンをクリックするとコンソールにメッセージを出力するだけの処理です。これを RxJS を使って Observable を生成する方法に書き換えてみます。

const button = document.querySelector('button');
Rx.Observable
  .fromEvent(button, 'click')
  .subscribe(
      (event: MouseEvent) => {
          console.log(`${(event.target as HTMLButtonElement).textContent} is clicked!!`);
      }
  );

順番に見ていきます。Observable ( ストリーム ) から fromEvent オペレータを使ってボタンのクリックイベントを取得し流せる仕組みを作ります。次にこの流れてくるイベントデータを subscribe ( 購読 ) メソッドを使って取り出しています。

こちらのデモで実際の動きをご覧いただけます。

See the Pen My first RxJS by wakamsha (@wakamsha) on CodePen.

Observabe.fromEvent

すでに何となくお分かりではないでしょうか。fromEvent は clickinput などといったイベントを操作するためのオペレータです。第一引数に DOM 要素、第二引数にイベント名を指定します。第一引数は any 型となっており、DOMElementだけでなくNodeList, jQuery element, Angular elementなど多種多様な型に対応しています。

Observable.subscribe

Observable はただ書いただけでは値を流しません。下流で subscribe ( 購読 ) することで初めて値が流れます4)Hot と Cold の概念につきましては他エントリにて改めて解説します。。subscribe メソッドは引数に Observer クラスを受け取りますが、以下のように3つの関数を直接受け取る書き方も可能です。Observer クラスのインスタンスは以下の3つの関数を内包したものなので、結局はどちらも同じというわけです。

subscribe(
  (x) => console.log(x),                    // onNext
  (error: Error) => console.error(error),   // onError
  () => console.log('Completed!!')          // onComplete
)

第一引数のonNextは新しい値が流れてきたときに、第二引数のonErrorはストリームの途中でエラーが発生したときに、第三引数のonCompleteは全ての値が流れきってストリームが終了した時にそれぞれ呼び出されます。

締め

RxJS を学ぶのは決して簡単ではありません。個人差はありますが、少なくともこれまでオブジェクト志向な世界に身をおいていた人にとっては『非常に難しい』部類に入るかと思います。その理由は膨大な API の数に加えて命令形から宣言型への根本的なコンセプトの変更があるからです。当ブログでは膨大な RxJS の世界から比較的よく使われるであろう機能やちょっとした TIPS などをかいつまんでご紹介できればと考えております。

今回は導入編ということで RxJS の簡単な概要とさわりだけをご紹介しました。次回からは RxJS の様々な機能をデモとともにご紹介するなど本格的なリアクティブ・プログラミングの世界に入っていきたいと思います。

参考リンク

なんだかんだ公式ドキュメントが一番です。チュートリアルもそこそこ充実しているので、まずは☝️を熟読するのをオススメします。ググれば日本語の情報もある程度ヒットしますが、その多くがバージョン 4.x の頃に書かれたものだったりします。そのため現行の 5.x だと動作しないコードが結構あるので注意が必要です。

脚注

脚注
1 オレ調べ。
2 他にも Java、Swift、Scala、C++、Ruby、Python、Groovy、JRuby、Kotlin などに移植されています。
3 僕は試していませんが、もちろん FlowType でも同様の恩恵を受けられると思います。
4 Hot と Cold の概念につきましては他エントリにて改めて解説します。