JavaScriptのリアクティブ拡張。 完全なガイド

Observable Collectionsを使用したいですか? リアクティブエクステンションについて聞いたことがありますか? LINQが好きですか? スパゲッティコードが嫌いですか? モナドが必要ですか? そして、これはすべてJavaScriptにありますか?

それでは、Rx for JavaScriptとは何ですか?
RxはReactive Extensionsの略です。 定義プロジェクトページで述べているように:
Rxは、Observerパターンに従って、コレクションを使用して非同期およびイベント指向のプログラムを作成するためのライブラリです。

主なアイデアは、非同期コンピューティングをデータソースとして考慮することです。 たとえば、コンピューターのマウスは、クリックやカーソルの動きのソースにすぎません。 Observable Collectionsは、このようなデータセットを操作するために使用されます。 RxJSのルーツは.NETの世界にあるため、一部のLINQ機能(select、where、take、skipなど)が利用可能になります。 これについては少し後で説明しますが、今のところは、ライブラリの構造を検討してください。

既存のフレームワークとの統合

開始するには、次のリンクから RxJSをダウンロードしてください 。 jQuery、MooTools、プロトタイプ、Dojo、ExtJS、およびGoogleマップなどの一般的なサービスを操作するための拡張機能が含まれています。 ライブラリ自体は、1つの7.4 kb rx.jsファイル(30 Kバイトの非圧縮)で構成されています。



例では、Web DeveloperパッケージがインストールされたVisual Studio 2010がエディターとして使用されます。 クライアントフレームワークはjQueryです。

したがって、単純なHTMLページを作成し、RxJSをプラグインします。

<head> <title>Samplestitle> <script type="text/javascript" src="Scripts\rx.js"></script> <head> 

その後、IntelliSenseはRxメソッドの表示を開始します。



理論のビット

先に進む前に、Rxで採用されている用語と規則のいくつかを明確にしたいと思います。

オブザーバー

上記のように、SubscribeメソッドはObservableイベントをサブスクライブするために使用されます。

 var source = null; var subscription = source.Subscribe( function (next) { console.log("OnNext: " + next); }, function (exn) { console.log("OnError: " + exn); }, function () { console.log("OnCompleted"); }); 

そして

 var source = Rx.Observable.Empty(); var observer = Rx.Observer.Create( function (data) { $(" ").text(data).appendTo("#content"); }); var handle = source.Subscribe(observer); 

Subscribeメソッドの詳細を検討してください。



オブザーバの登録を解除するための個別の方法はありません。 代わりに、Disposeパターンは.NET環境からRxJSに導入されました。
したがって、オブザーバーのリンク(ハンドル)にはDisposeメソッドが含まれており、これを呼び出すことでオブジェクトを破棄できます。



オブザーバブル

ほとんどの場合、Webサービスの呼び出しであろうと、DOM要素を使用する場合であっても、常に「ホット」ブラウザを使用します。 実際のアプリケーションの「コールド」ブラウザはそれほど一般的ではありませんが、ユニットテスト中にその目的が明確になります-事前に準備されたデータセットを操作します。
以下は、Observableとその説明を作成するためのAPIテーブルです。
メソッド名説明
空()OnCompletedを呼び出す空のコレクションを返します
投げる(error_msg)OnError呼び出しで空のコレクションを返します
戻り値(値)1つのアイテムのコレクションを返します
範囲(開始、カウント)32ビット整数の配列を返します
生成(initial_state、condition、selector、iterate)次のパラメーターで作成されたコレクションを返します
GenerateWithTime(時間)Generateメソッドに似ていますが、要素の生成間に時間間隔を追加します
なし()イベントを呼び出さずに空のコレクションを返します
toObservable(event_name)jQueryオブジェクトを操作するための拡張機能
FromArray()JS配列からコレクションを初期化します
作成(subscribe_detail)オブザーバーサブスクリプションの詳細のコレクションを作成します
FromDOMEvent(dom_element、event_name)DOM要素を操作するための拡張機能
FromIEEvent(dom_element、event_name)Internet ExplorerのDOM要素の特定のイベントを操作するための拡張機能
FromHtmlEvent(dom_element、event_name)FromDOMEvent()およびFromIEEvent()の汎用メソッドです

LINQ

そのため、RxJSの最も興味深い機能の1つであるLINQサポートにアクセスします。 .NETプラットフォームで利用できるこのすばらしい技術について多くの人が聞いたことがあると思います。
LINQはLanguage Integrated Queryの略で、さまざまなコレクションを照会できます。 RxJSの出現により、すべてのメソッドがJavaScriptの世界にもたらされたわけではありませんが、最も有用なものは次のとおりです。

新しいものが追加され、ここにのみ表示されます。

完全なリストは提供しません。なぜなら 残りのメソッドは自分で確認できます。
以下の図をより明確に理解するために、イベントのサブスクリプションの図を示します。



JavaScriptにはラムダ式が存在しないため、LINQメソッドのパラメーターとしての役割は通常の関数によって実行されます。

 var items = [1, 2, 3, 4, 5]; var observable = Rx.Observable.FromArray(items).Select(function (item) { return { Value: item, Sqrt: Math.sqrt(item) }; }).Where(function (item) { return item.Value + 2 < 5; }); 

新しい関数(DistinctUntilChanged、Throttleなど)に戻り、それらの非常に有用な機能に注目したいと思います。 そのため、状況によってはsetIntervalとsetTimeoutを使用してThrottleが置き換えられ、DistinctUntilChangedと組み合わせて使用​​すると、たとえば、テキスト入力時のajaxリクエストの数が減少します。
そして、例のための視覚的なコード:

 var input = $("#textbox").toObservable("keyup") .Select(function (event) { return $(event.target).val(); }) .Timestamp() .Do(function (inp) { var text = "I: " + inp.Timestamp + "-" + inp.Value; $(" ").text(text).appendTo("#content"); }) .RemoveTimestamp() .Throttle(1000) .Timestamp() .Do(function (inp) { var text = "T: " + inp.Timestamp + "-" + inp.Value; $(" ").text(text).appendTo("#content"); }) .RemoveTimestamp() .DistinctUntilChanged(); var subscribtion = input.Subscribe(function (data) { $(" ").text("Your text: " + data).appendTo("#content"); }); 

したがって、DistinctUntilChangedを呼び出してテキストフィールド値の配列を渡す前に、何らかのログを記録します。

スパゲッティコードにノーと言う!

記事のこの最後の部分では、すでに何度か言及されているWebサービスの操作を検討したいと思います。
このコードについて何回書いていますか:

 $.ajax({ url: "your_url", dataType: "json", success: function (data, textStatus, xhr) { $("#results").empty(); $.each(data[1], function (_, result) { $("#results").append(" " + result + " "); }); }, error: function (xhr, textStatus, errorThrown) { $("#error").text(errorThrown); } }); 

かなり頻繁に思います。 彼の問題は何ですか? そうです、データ処理ロジックはデータソースの定義と共にカプセル化され、「スパゲッティコード」になります。
RxJSはこの問題を解決します。 最初に、jQueryと統合するための拡張機能であるrx.jQueryファイルを含める必要があります。
その後、上記のコードを少しリファクタリングします。

 function serviceCall(text) { return $.ajaxAsObservable( { url: "your_url", dataType: "json", format: "json", data: text }); } var source = serviceCall("search me"); var handle = source.Subscribe(function (result) { $("#results").append(" " + result + " "); }, function (exn) { $("#error").text(exn); }); 

したがって、リクエスト自体からデータ処理ロジックを分離し、リクエスト自体を本質的にラップしました。

あとがき

この記事では、JavaScriptライブラリーのReactive Extensionsの力を示したかったのです。 その適用範囲は非常に広範囲で、プログラマーのニーズによってのみ決定されます。 私自身の経験から言えば、Observable CollectionsとRxJSの哲学自体は、すでに確立されているコード作成プラクティスのレビューを必要としていますが、それだけの価値はあります。
単体テスト、操作のキャンセル、およびSelectMany演算子は考慮されませんでした(モナドが表示される場所です)が、それについては次の記事で詳しく説明します。

PS

いくつかのポイントをより詳細に説明する便利なリンクのリスト:

Source: https://habr.com/ru/post/J132463/


All Articles