著者は、 Write for DOnations プログラムの一環として、 MozillaFoundationを選択して寄付を受け取りました。

序章

リアクティブプログラミングは、非同期データストリームに関連するパラダイムであり、プログラミングモデルはすべてを時間の経過とともに広がるデータストリームと見なします。 これには、キーストローク、HTTPリクエスト、印刷されるファイル、さらには配列の要素も含まれます。これらは、非常に短い間隔でタイミングが取られていると見なすことができます。 この言語では非同期データが一般的であるため、JavaScriptに最適です。

RxJS は、JavaScriptのリアクティブプログラミングで人気のあるライブラリです。 RxJSの傘であるReactiveXは、 Java Python C ++ などの他の多くの言語で拡張されています。 Swift 、およびDart。 RxJSは、AngularやReactなどのライブラリでも広く使用されています。

RxJSの実装は、一定期間のデータを認識して処理できる連鎖関数に基づいています。 これは、引数とコールバックのリストを受け取る関数だけでRxJSのほぼすべての側面を実装し、そうするように指示されたときにそれらを実行できることを意味します。 RxJSを取り巻くコミュニティはこの手間のかかる作業を行っており、その結果、あらゆるアプリケーションで直接使用して、クリーンで保守可能なコードを記述できるAPIが作成されています。

このチュートリアルでは、RxJSを使用して、リアルタイムの結果をユーザーに返す機能豊富な検索バーを作成します。 また、HTMLとCSSを使用して検索バーをフォーマットします。 最終結果は次のようになります。

Demonstration of Search Bar

検索バーのように一般的で一見シンプルに見えるものには、さまざまなチェックを行う必要があります。 このチュートリアルでは、RxJSが、かなり複雑な一連の要件を、管理しやすく理解しやすいコードに変換する方法を示します。

前提条件

このチュートリアルを開始する前に、次のものが必要です。

チュートリアルの完全なコードは、Githubで入手できます。

このステップでは、HTMLとCSSを使用して検索バーを作成し、スタイルを設定します。 このコードは、 Bootstrap のいくつかの一般的な要素を使用して、ページの構造化とスタイル設定のプロセスを高速化し、カスタム要素の追加に集中できるようにします。 Bootstrap は、タイポグラフィ、フォーム、ボタン、ナビゲーション、グリッド、その他のインターフェイスコンポーネントなどの一般的な要素のテンプレートを含むCSSフレームワークです。 アプリケーションはAnimate.cssを使用して、検索バーにアニメーションを追加します。

まず、nanoまたはお気に入りのテキストエディタを使用してsearch-bar.htmlという名前のファイルを作成します。

  1. nano search-bar.html

次に、アプリケーションの基本構造を作成します。 次のHTMLを新しいファイルに追加します。

search-bar.html
<!DOCTYPE html>
<html>

  <head>
    <title>RxJS Tutorial</title>
    <!-- Load CSS -->

    <!-- Load Rubik font -->

    <!-- Add Custom inline CSS -->

  </head>

  <body>
      <!-- Content -->

      <!-- Page Header and Search Bar -->

      <!-- Results -->

      <!-- Load External RxJS -->

      <!-- Add custom inline JavaScript -->
      <script>

      </script>
  </body>

</html>

Bootstrapライブラリ全体からCSSが必要なため、先に進んでBootstrapとAnimate.cssのCSSをロードします。

Load CSSコメントの下に次のコードを追加します。

search-bar.html
...
<!-- Load CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" crossorigin="anonymous">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.7.0/animate.min.css" />
...

このチュートリアルでは、 GoogleFontsライブラリのRubikというカスタムフォントを使用して、検索バーのスタイルを設定します。 Load Rubik fontコメントの下に強調表示されたコードを追加して、フォントをロードします。

search-bar.html
...
<!-- Load Rubik font -->
    <link href="https://fonts.googleapis.com/css?family=Rubik" rel="stylesheet">
...

次に、Add Custom inline CSSコメントの下のページにカスタムCSSを追加します。 これにより、ページの見出し、検索バー、および結果が読みやすく、使いやすくなります。

search-bar.html
...
<!-- Add Custom inline CSS -->
    <style>
      body {
        background-color: #f5f5f5;
        font-family: "Rubik", sans-serif;
      }
      
      .search-container {
        margin-top: 50px;
      }
      .search-container .search-heading {
        display: block;
        margin-bottom: 50px;
      }
      .search-container input,
      .search-container input:focus {
        padding: 16px 16px 16px;
        border: none;
        background: rgb(255, 255, 255);
        box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1) !important;
      }

      .results-container {
        margin-top: 50px;
      }
      .results-container .list-group .list-group-item {
        background-color: transparent;
        border-top: none !important;
        border-bottom: 1px solid rgba(236, 229, 229, 0.64);
      }

      .float-bottom-right {
        position: fixed;
        bottom: 20px;
        left: 20px;
        font-size: 20px;
        font-weight: 700;
        z-index: 1000;
      }
      .float-bottom-right .info-container .card {
        display: none;
      }
      .float-bottom-right .info-container:hover .card,
      .float-bottom-right .info-container .card:hover {
        display: block;
      }
    </style>
...

すべてのスタイルが配置されたので、Page Header and Search Barコメントの下にヘッダーと入力バーを定義するHTMLを追加します。

search-bar.html
...
<!-- Content -->
<!-- Page Header and Search Bar -->
      <div class="container search-container">
        <div class="row justify-content-center">
          <div class="col-md-auto">
            <div class="search-heading">
              <h2>Search for Materials Published by Author Name</h2>
              <p class="text-right">powered by <a href="https://www.crossref.org/">Crossref</a></p>
            </div>
          </div>
        </div>
        <div class="row justify-content-center">
          <div class="col-sm-8">
            <div class="input-group input-group-md">
              <input id="search-input" type="text" class="form-control" placeholder="eg. Richard" aria-label="eg. Richard" autofocus>
            </div>
          </div>
        </div>
      </div>
...

これは、Bootstrapのグリッドシステムを使用して、ページヘッダーと検索バーを構成します。 search-input識別子を検索バーに割り当てました。これは、チュートリアルの後半でリスナーにバインドするために使用します。

次に、検索結果を表示する場所を作成します。 Resultsコメントの下に、response-list識別子を使用してdivを作成し、チュートリアルの後半で結果を追加します。

search-bar.html
...
<!-- Results -->
      <div class="container results-container">
        <div class="row justify-content-center">
          <div class="col-sm-8">
            <ul id="response-list" class="list-group list-group-flush"></ul>
          </div>
        </div>
      </div>
...

この時点で、search-bar.htmlファイルは次のようになります。

search-bar.html
<!DOCTYPE html>
<html>

  <head>
    <title>RxJS Tutorial</title>
    <!-- Load CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" crossorigin="anonymous">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.7.0/animate.min.css" />

    <!-- Load Rubik font -->
    <link href="https://fonts.googleapis.com/css?family=Rubik" rel="stylesheet">
    
    <!-- Add Custom inline CSS -->
    <style>
      body {
        background-color: #f5f5f5;
        font-family: "Rubik", sans-serif;
      }
      
      .search-container {
        margin-top: 50px;
      }
      .search-container .search-heading {
        display: block;
        margin-bottom: 50px;
      }
      .search-container input,
      .search-container input:focus {
        padding: 16px 16px 16px;
        border: none;
        background: rgb(255, 255, 255);
        box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1) !important;
      }

      .results-container {
        margin-top: 50px;
      }
      .results-container .list-group .list-group-item {
        background-color: transparent;
        border-top: none !important;
        border-bottom: 1px solid rgba(236, 229, 229, 0.64);
      }

      .float-bottom-right {
        position: fixed;
        bottom: 20px;
        left: 20px;
        font-size: 20px;
        font-weight: 700;
        z-index: 1000;
      }
      .float-bottom-right .info-container .card {
        display: none;
      }
      .float-bottom-right .info-container:hover .card,
      .float-bottom-right .info-container .card:hover {
        display: block;
      }
    </style>
  </head>

  <body>
      <!-- Content -->
      <!-- Page Header and Search Bar -->
      <div class="container search-container">
        <div class="row justify-content-center">
          <div class="col-md-auto">
            <div class="search-heading">
              <h2>Search for Materials Published by Author Name</h2>
              <p class="text-right">powered by <a href="https://www.crossref.org/">Crossref</a></p>
            </div>
          </div>
        </div>
        <div class="row justify-content-center">
          <div class="col-sm-8">
            <div class="input-group input-group-md">
              <input id="search-input" type="text" class="form-control" placeholder="eg. Richard" aria-label="eg. Richard" autofocus>
            </div>
          </div>
        </div>
      </div>

      <!-- Results -->
      <div class="container results-container">
        <div class="row justify-content-center">
          <div class="col-sm-8">
            <ul id="response-list" class="list-group list-group-flush"></ul>
          </div>
        </div>
      </div>

      <!-- Load RxJS -->

      <!-- Add custom inline JavaScript -->
      <script>

      </script>
  </body>

</html>

このステップでは、HTMLとCSSを使用して検索バーの基本構造をレイアウトしました。 次のステップでは、検索語を受け入れて結果を返すJavaScript関数を記述します。

ステップ2—JavaScriptを書く

検索バーのフォーマットが完了したので、このチュートリアルの後半で作成するRxJSコードの基盤として機能するJavaScriptコードを作成する準備が整いました。 このコードはRxJSと連携して、検索語を受け入れ、結果を返します。

このチュートリアルではBootstrapとJavaScriptが提供する機能は必要ないため、それらをロードすることはありません。 ただし、RxJSを使用します。 Load RxJSコメントの下に以下を追加して、RxJSライブラリをロードします。

search-bar.html
...
<!-- Load RxJS -->
    <script src="https://unpkg.com/@reactivex/[email protected]/dist/global/Rx.js"></script>
...

次に、結果が追加されるHTMLからのdivの参照を保存します。 Add custom inline JavaScriptコメントの下の<script>タグに強調表示されたJavaScriptコードを追加します。

search-bar.html
...
<!-- Add custom inline JavaScript -->
<script>
        const output = document.getElementById("response-list");

</script>
...

次に、APIからのJSON応答をページに表示するHTML要素に変換するコードを追加します。 このコードは、最初に検索バーの内容をクリアしてから、検索結果のアニメーションの遅延を設定します。

<script>タグの間に強調表示された関数を追加します。

search-bar.html
...
<!-- Add custom inline JavaScript -->
<script>
    const output = document.getElementById("response-list");

        function showResults(resp) {
        var items = resp['message']['items']
        output.innerHTML = "";
        animationDelay = 0;
        if (items.length == 0) {
          output.innerHTML = "Could not find any :(";
        } else {
          items.forEach(item => {
            resultItem = `
            <div class="list-group-item animated fadeInUp" style="animation-delay: ${animationDelay}s;">
              <div class="d-flex w-100 justify-content-between">
<^>                <h5 class="mb-1">${(item['title'] && item['title'][0]) || "&lt;Title not available&gt;"}</h5>
              </div>
              <p class="mb-1">${(item['container-title'] && item['container-title'][0]) || ""}</p>
              <small class="text-muted"><a href="${item['URL']}" target="_blank">${item['URL']}</a></small>
              <div> 
                <p class="badge badge-primary badge-pill">${item['publisher'] || ''}</p>
                <p class="badge badge-primary badge-pill">${item['type'] || ''}</p> 
             </div>
            </div>
            `;
            output.insertAdjacentHTML("beforeend", resultItem);
            animationDelay += 0.1; 
                                   
          });
        }
      }

</script>
...

ifで始まるコードブロックは、検索結果をチェックし、結果が見つからなかった場合にメッセージを表示する条件付きループです。 結果が見つかった場合、forEachループは結果にアニメーションをユーザーに提供します。

このステップでは、結果を受け入れてページに返すことができる関数を記述して、RxJSのベースをレイアウトしました。 次のステップでは、検索バーを機能させます。

ステップ3—リスナーを設定する

RxJSは、データストリームに関係しています。このプロジェクトでは、ユーザーが入力要素または検索バーに入力する一連の文字です。 このステップでは、入力要素にリスナーを追加して、更新をリッスンします。

まず、チュートリアルの前半で追加したsearch-input識別子に注意してください。

search-bar.html
...
<input id="search-input" type="text" class="form-control" placeholder="eg. Richard" aria-label="eg. Richard" autofocus>
...

次に、search-input要素の参照を保持する変数を作成します。 これは、コードが入力イベントをリッスンするために使用するObservableになります。 Observablesは、Observerがリッスンする将来の値またはイベントのコレクションであり、コールバック関数とも呼ばれます。

前の手順のJavaScriptの下にある<script>タグに強調表示された行を追加します。

search-bar.html
...
      output.insertAdjacentHTML("beforeend", resultItem);
      animationDelay += 0.1; 

    });
  }
}


      let searchInput = document.getElementById("search-input");
...

入力を参照する変数を追加したので、fromEvent演算子を使用してイベントをリッスンします。 これにより、特定の種類のイベントの要素であるDOMまたはD ocument O bject Modelにリスナーが追加されます。 DOM要素は、ページ上のhtmlbodydiv、またはimg要素である可能性があります。 この場合、DOM要素は検索バーです。

searchInput変数の下に次の強調表示された行を追加して、パラメーターをfromEventに渡します。 searchInputDOM要素が最初のパラメーターです。 この後に、2番目のパラメーターとしてinputイベントが続きます。これは、コードがリッスンするイベントタイプです。

search-bar.html
...
      let searchInput = document.getElementById("search-input");
      Rx.Observable.fromEvent(searchInput, 'input')
...

リスナーが設定されたので、入力要素で更新が行われるたびにコードは通知を受け取ります。 次のステップでは、演算子を使用してそのようなイベントに対してアクションを実行します。

ステップ4—演算子を追加する

Operatorsは、データに対して操作を実行するという1つのタスクを持つ純粋関数です。 このステップでは、演算子を使用して、inputパラメーターのバッファリング、HTTPリクエストの作成、結果のフィルタリングなどのさまざまなタスクを実行します。

まず、ユーザーがクエリを入力すると、結果がリアルタイムで更新されることを確認します。 これを実現するには、前の手順のDOM入力イベントを使用します。 DOM入力イベントにはさまざまな詳細が含まれていますが、このチュートリアルでは、ターゲット要素に入力された値に関心があります。 次のコードを追加して、pluck演算子を使用してオブジェクトを取得し、指定されたキーの値を返します。

search-bar.html
...
      let searchInput = document.getElementById("search-input");
      Rx.Observable.fromEvent(searchInput, 'input')
        .pluck('target', 'value')
...

イベントが必要な形式になっているので、検索語の最小値を3文字に設定します。 多くの場合、3文字未満では関連する結果が得られないか、ユーザーがまだ入力中である可能性があります。

filter演算子を使用して最小値を設定します。 指定された条件を満たす場合、データはさらに下流に渡されます。 長さ条件を2より大きく設定して、少なくとも3文字を必要とします。

search-bar.html
...
      let searchInput = document.getElementById("search-input");
      Rx.Observable.fromEvent(searchInput, 'input')
        .pluck('target', 'value')
        .filter(searchTerm => searchTerm.length > 2)
...

また、APIサーバーの負荷を軽減するために、リクエストが500ミリ秒間隔でのみ送信されるようにします。 これを行うには、debounceTime演算子を使用して、ストリームを通過する各イベント間の最小指定間隔を維持します。 filter演算子の下に強調表示されたコードを追加します。

search-bar.html
...
      let searchInput = document.getElementById("search-input");
      Rx.Observable.fromEvent(searchInput, 'input')
        .pluck('target', 'value')
        .filter(searchTerm => searchTerm.length > 2)
        .debounceTime(500)
...

最後のAPI呼び出し以降に変更がない場合、アプリケーションは検索語も無視する必要があります。 これにより、送信されるAPI呼び出しの数がさらに減り、アプリケーションが最適化されます。

たとえば、ユーザーはsuper carsと入力し、最後の文字を削除して(super carという用語を作成)、削除した文字を追加して、用語をsuper carsに戻すことができます。 。 その結果、用語は変更されなかったため、検索結果は変更されません。 このような場合、操作を実行しないことは理にかなっています。

これを構成するには、distinctUntilChanged演算子を使用します。 この演算子は、ストリームを介して渡された以前のデータを記憶し、異なる場合にのみ別のデータを渡します。

search-bar.html
...
      let searchInput = document.getElementById("search-input");
      Rx.Observable.fromEvent(searchInput, 'input')
        .pluck('target', 'value')
        .filter(searchTerm => searchTerm.length > 2)
        .debounceTime(500)
        .distinctUntilChanged()
...

ユーザーからの入力を規制したので、検索語を使用してAPIにクエリを実行するコードを追加します。 これを行うには、AJAXのRxJS実装を使用します。 AJAXは、ロードされたページのバックグラウンドでAPI呼び出しを非同期的に行います。 AJAXを使用すると、新しい検索用語の結果でページを再読み込みすることを回避でき、サーバーからデータをフェッチすることでページの結果を更新することもできます。

次に、switchMapを使用してAJAXをアプリケーションにチェーンするコードを追加します。 また、mapを使用して、入力を出力にマップします。 このコードは、渡された関数をObservableによって発行されたすべてのアイテムに適用します。

search-bar.html
...
      let searchInput = document.getElementById("search-input");
      Rx.Observable.fromEvent(searchInput, 'input')
        .pluck('target', 'value')
        .filter(searchTerm => searchTerm.length > 2)
        .debounceTime(500)
        .distinctUntilChanged()
        .switchMap(searchKey => Rx.Observable.ajax(`https://api.crossref.org/works?rows=50&query.author=${searchKey}`)
          .map(resp => ({
              "status" : resp["status"] == 200,
              "details" : resp["status"] == 200 ? resp["response"] : [],
              "result_hash": Date.now()
            })
          )
        )
...

このコードは、API応答を次の3つの部分に分割します。

  • status:APIサーバーから返されたHTTPステータスコード。 このコードは、200または成功した応答のみを受け入れます。
  • details:受信した実際の応答データ。 これには、クエリされた検索語の結果が含まれます。
  • result_hash:APIサーバーによって返される応答のハッシュ値。このチュートリアルの目的ではUNIXタイムスタンプです。 これは、結果が変更されたときに変更される結果のハッシュです。 一意のハッシュ値により、アプリケーションは結果が変更されており、更新する必要があるかどうかを判断できます。

システムに障害が発生したため、エラーを処理できるようにコードを準備する必要があります。 API呼び出しで発生する可能性のあるエラーを処理するには、filter演算子を使用して、成功した応答のみを受け入れます。

search-bar.html
...
      let searchInput = document.getElementById("search-input");
      Rx.Observable.fromEvent(searchInput, 'input')
        .pluck('target', 'value')
        .filter(searchTerm => searchTerm.length > 2)
        .debounceTime(500)
        .distinctUntilChanged()
        .switchMap(searchKey => Rx.Observable.ajax(`https://api.crossref.org/works?rows=50&query.author=${searchKey}`)
          .map(resp => ({
              "status" : resp["status"] == 200,
              "details" : resp["status"] == 200 ? resp["response"] : [],
              "result_hash": Date.now()
            })
          )
        )
        .filter(resp => resp.status !== false)
...

次に、応答で変更が検出された場合にのみDOMを更新するコードを追加します。 DOMの更新はリソースを大量に消費する操作になる可能性があるため、更新の数を減らすと、アプリケーションにプラスの影響があります。 result_hashは応答が変更された場合にのみ変更されるため、この機能を実装するために使用します。

これを行うには、前と同じようにdistinctUntilChanged演算子を使用します。 コードはこれを使用して、キーが変更された場合にのみユーザー入力を受け入れます。

search-bar.html
...
      let searchInput = document.getElementById("search-input");
      Rx.Observable.fromEvent(searchInput, 'input')
        .pluck('target', 'value')
        .filter(searchTerm => searchTerm.length > 2)
        .debounceTime(500)
        .distinctUntilChanged()
        .switchMap(searchKey => Rx.Observable.ajax(`https://api.crossref.org/works?rows=50&query.author=${searchKey}`)
          .map(resp => ({
              "status" : resp["status"] == 200,
              "details" : resp["status"] == 200 ? resp["response"] : [],
              "result_hash": Date.now()
            })
          )
        )
        .filter(resp => resp.status !== false)
        .distinctUntilChanged((a, b) => a.result_hash === b.result_hash)
...

以前はdistinctUntilChanged演算子を使用してデータ全体が変更されたかどうかを確認しましたが、この場合は、応答で更新されたキーを確認します。 応答全体を比較することは、単一のキーの変更を識別することと比較すると、リソースコストがかかります。 キーハッシュは応答全体を表すため、応答の変更を識別するために自信を持って使用できます。

この関数は、以前に見た値と新しい値の2つのオブジェクトを受け入れます。 これらの2つのオブジェクトからハッシュをチェックし、これら2つの値が一致すると、Trueを返します。この場合、データはフィルターで除外され、パイプラインでそれ以上渡されません。

このステップでは、ユーザーが入力した検索語を受け取り、それに対してさまざまなチェックを実行するパイプラインを作成しました。 チェックが完了すると、API呼び出しが行われ、結果をユーザーに表示する形式で応答が返されます。 必要に応じてAPI呼び出しを制限することにより、クライアント側とサーバー側の両方でリソースの使用を最適化しました。 次のステップでは、入力要素のリッスンを開始するようにアプリケーションを構成し、その結果をページにレンダリングする関数に渡します。

ステップ5—サブスクリプションですべてをアクティブ化する

subscribeは、Observableによって発行されたデータイベントをオブザーバーが確認できるようにするリンクの最後の演算子です。 次の3つのメソッドを実装します。

  • onNext:イベントを受信したときに何をするかを指定します。
  • onError:これはエラーの処理を担当します。 onNextおよびonCompletedの呼び出しは、このメソッドが呼び出されると行われません。
  • onCompleted:このメソッドは、onNextが最後に呼び出されたときに呼び出されます。 パイプラインで渡されるデータはこれ以上ありません。

サブスクライバーのこの署名により、レイジー実行を実現できます。これは、Observableパイプラインを定義し、サブスクライブした場合にのみ動作させる機能です。 この例をコードで使用することはありませんが、Observableをサブスクライブする方法を以下に示します。

次に、Observableをサブスクライブし、UIでのレンダリングを担当するメソッドにデータをルーティングします。

search-bar.html
...
      let searchInput = document.getElementById("search-input");
      Rx.Observable.fromEvent(searchInput, 'input')
        .pluck('target', 'value')
        .filter(searchTerm => searchTerm.length > 2)
        .debounceTime(500)
        .distinctUntilChanged()
        .switchMap(searchKey => Rx.Observable.ajax(`https://api.crossref.org/works?rows=50&query.author=${searchKey}`)
          .map(resp => ({
              "status" : resp["status"] == 200,
              "details" : resp["status"] == 200 ? resp["response"] : [],
              "result_hash": Date.now()
            })
          )
        )
        .filter(resp => resp.status !== false)
        .distinctUntilChanged((a, b) => a.result_hash === b.result_hash)
        .subscribe(resp => showResults(resp.details));
...

これらの変更を行った後、ファイルを保存して閉じます。

コードの記述が完了したので、検索バーを表示してテストする準備が整いました。 search-bar.htmlファイルをダブルクリックして、Webブラウザで開きます。 コードが正しく入力されている場合は、検索バーが表示されます。

The completed search bar

検索バーにコンテンツを入力してテストします。

A gif of content being entered into the search bar, showing that two characters won't return any results.

このステップでは、Observableにサブスクライブしてコードをアクティブ化しました。 これで、定型化され機能する検索バーアプリケーションができました。

結論

このチュートリアルでは、ユーザーにリアルタイムの結果を提供するRxJS、CSS、およびHTMLを使用して機能豊富な検索バーを作成しました。 検索バーには最低3文字が必要で、自動的に更新され、クライアントとAPIサーバーの両方に最適化されています。

複雑な要件のセットと見なすことができるものは、18行のRxJSコードで作成されました。 このコードは読みやすいだけでなく、スタンドアロンのJavaScript実装よりもはるかにクリーンです。 これは、コードが将来的に理解、更新、および保守しやすくなることを意味します。

RxJSの使用の詳細については、公式APIドキュメントをご覧ください。