はじめに
この記事はアイスタイル Advent Calendar 2024 7日目の記事です。
アットコスメ のバックエンド開発を担当しているkuriyamayです。
今年もアドベントカレンダーへの参加となります。
過去の記事はこちらから。
- 2020年
kubernetes(k8s)を構築してデプロイやスケールで遊んでみた - 2021年
Java SE 11(Java Silver)を受験した話 - 2022年
curry化と部分適用をJavaで
curry化と部分適用をJavaで ~命名編~ - 2023年
CQRSとEventSourcingに挑戦
今年はRxJSについてつらつらと書いていこうと思います。
RxJSへのきっかけ
もともとはJavaのSpring WebFluxを使ってリアクティブプログラミングを学んでいました。
その後、業務で新しいアプリケーションを作成する機会があり、Node.js(TypeScript)とNestJSを採用したことをきっかけに、RxJSの学習を始めました。
NestJSは公式でRxJSをサポートしており、フレームワーク内部でRxJSを利用しています。
そのため、非同期処理を扱う際にObservablesを使用できます。
せっかくNestJSを選んだので、RxJSの利点を活かしたアプリケーションを作りたいと思い、より深く学ぶことを決めました。
RxJSの概要と魅力
RxJSとは何か
RxJS(Reactive Extensions for JavaScript)は、イベントや非同期処理を「データストリーム」として扱うための強力なライブラリです。
特徴は以下の通りです:
- Reactive Extensions for JavaScriptの略称
- イベントや非同期処理をデータストリームとして扱う
- Rxの概念は多くの言語で共通
- 例: RxJava(Java用)、RxPy(Python用)、RxAndroid(Android用)、RxKotlin(Kotlin用)
公式ドキュメント: RxJS Documentation
また、Spring WebFluxはJava向けのリアクティブなWebフレームワークで、似たようなリアクティブプログラミングの概念を採用しています。
Spring WebFlux公式: Spring WebFlux Documentation
なぜRxJSを使うのか
Rxの概念を学べば、他の言語やフレームワーク(例: AngularやReact)でも応用可能です。
また、RxJSを使うことで、以下のメリットが得られます:
- 宣言的なコードが書ける: 複雑な処理もシンプルに記述可能
- 非同期処理に強い: イベント、タイマー、APIレスポンスなどを一貫したインターフェースで扱える
- リアルタイム処理に最適: マイクロサービスやリアルタイムアプリケーションの開発に向いている
RxJSの基本概念
リアクティブプログラミングとは
リアクティブプログラミングは、データの流れ(ストリーム)と変化に反応するプログラミングパラダイムです。
その特徴は以下の通りです:
- データの変化に応じて自動的に処理が実行される
- 命令型プログラミングと対比される宣言型のアプローチ
- 非同期処理やイベント駆動型システムの設計に適している
リアクティブプログラミングでは、すべてのデータ(イベント・タイマー・APIレスポンスなど)は「ストリーム」として扱われ、即座に反応できる仕組みが特徴です。
Observable/Observer/Subscription
RxJSの基本要素を見てみましょう。
- Observable
- データストリームの「作成者」
- データの流れ(イベント)を定義
- 遅延実行型:subscribeを呼び出すまで実行されない
- Observer
- データストリームの「受信者」
- next(データの受信)、error(エラー)、complete(完了)の3つのメソッドを持つ
- Subscription
- ストリームの「コントローラー」
- unsubscribeを呼び出すことでストリームを停止できる
以下は具体例です:
// Observableを作成
const observable = new Observable((subscriber) => {
// データを次のストリームへ送信
subscriber.next(1);
subscriber.next(2);
subscriber.complete(); // 完了を通知する
});
// Observableを購読(subscribe)
observable.subscribe({
next: (value) => console.log(`Next: ${value}`), // 値を受信した場合に実行
error: (err) => console.error(`Error: ${err}`), // エラー発生時に実行
complete: () => console.log('Completed'), // ストリームが完了した時に実行
});
RxJSの動作原理
配列とRxJSの違いを比較しながら、内部的な挙動を見ていきます。
通常の配列
const result = [1, 2, 3].map((x) => x * 2);
console.log(result); // 出力: 2, 4, 6
RxJSのObservable
of(1, 2, 3)
.pipe(map((value) => value * 2))
.subscribe(console.log); // 出力: 2, 4, 6
配列とObservableの違い
出力結果は同じですが、Observableは遅延実行を採用しており、非同期データを効率的に扱う点で配列とは根本的に異なります。
次に、配列とObservableの違いを表で見てみましょう。
特徴 | 配列 | Observable |
---|---|---|
実行タイミング | 即時実行 | 遅延実行 (subscribeで開始) |
データの扱い | 静的データ(同期的) | ストリーム(同期/非同期両対応) |
再利用性 | 配列は状態を保持しない | Observableは再利用可能 |
Observableは非同期処理に対応している点が大きな特徴です。
たとえば、リアルタイムデータやAPIレスポンスのような動的データを一貫したインターフェースで扱うことができます。
また、subscribeを呼び出すたびに新しいストリームを開始できるため、同じ処理を再利用するのも容易です。
まとめ
- RxJSの学習コストは高いがその価値はある
- 一度習得すれば他言語やフレームワークでも応用可能
- ストリームの流れを意識した宣言的なコードを書けると楽しい
最後まで読んでいただき、ありがとうございました!
引き続きアイスタイル Advent Calendar 2024 をお楽しみください。