Rx レスポンシブプログラミングについての簡単な説明

Rx レスポンシブプログラミングについての簡単な説明

1. 観察可能

Observable は文字通り「観察可能」という意味で、言い換えれば「データ ソース」または「イベント ソース」の一種です。このデータ ソースには観察できる機能があり、これはデータを積極的に収集することとは根本的に異なります。わかりやすい比喩を使うと、Observable は蛇口のようなものです。蛇口をオンにして Observable をサブスクライブすると、水、つまりデータが継続的に流れ出ます。これが、能動的から受動的に変化すること、つまりレスポンシブプログラミングの中心的な考え方です。ただし、この記事ではこれについては詳しく説明しません。

Observable は、さまざまな方法で実装できる概念です。この記事では、高階関数を使用して、よく使用される 2 つの Observable、fromEvent と Interval を実装します。 Observable へのサブスクライブとサブスクライブ解除という 2 つの動作を説明することで、読者が Observable が何であるかを真に理解できるようになります。

2. 高階関数

高階関数の概念は関数型プログラミングから来ています。簡単に定義すると、関数の入力パラメータまたは戻り値は関数の関数であるということです。例えば:

関数foo(arg){
    関数()を返す{
        console.log(引数)
    }
}
const bar = foo("hello world")
bar() // こんにちは世界

ps: 高階関数で実行できることは多数ありますが、ここではこの記事で必要な状況にのみ使用されます。

上記の foo 関数の呼び出しは、hello world を直接印刷するのではなく、hello world をキャッシュするだけです。その後、実際のニーズに応じて返された bar 関数を呼び出し、実際に hello world を出力する作業を実行します。

なぜこのパッケージングの手順を実行する必要があるのでしょうか?実際、これを行うと、通話が「遅延」されます。そして、すべての本質は「遅延」という言葉にあります。本質的には、配達ボックスのように、動作を一貫したもののようにパッケージ化しています。

中にはいろいろなものを入れることができますが、物流上は統一されたものになります。そのため、宅配ボックスの積み重ね、輸送、保管、さらにはボックスの開封動作まで一貫した統一された操作が可能になります。

前の例に戻ると、foo 関数を呼び出すことは、宅配ボックスを梱包することと同じです。宅配ボックスには固定プログラムがあり、宅配ボックスが開かれると (bar を呼び出す) 印刷操作が実行されます。

foo1、foo2、foo3 などがあります。さまざまなプログラムがありますが、これらの foo には共通の操作である「open」があります。 (前提として、foo は関数を返すため、「open」操作が満たされ、返された関数が呼び出されます)。

関数foo1(arg){
    関数()を返す{
       console.log(引数+"?")
    }
}
関数foo2(arg){
      関数()を返す{
         console.log(引数+"!")
     }
}
const bar1 = foo1("こんにちは世界")
const bar2 = foo2("はい")
bar1()+bar2() // こんにちは、世界? はい!

3. エクスプレスボックスモデル

3.1. エクスプレスボックスモデル1: fromEvent

上記を基礎として、Rx プログラミングで最もよく使用される Observable である fromEvent(……) を見てみましょう。 Rx プログラミングの初心者にとって、最初は fromEvent(...) と addEventListener(...) の違いを理解するのは難しいです。

btn.addEventListener("クリック",コールバック)
rx.fromEvent(btn,"click").subscribe(コールバック)

このコードを直接実行すると、効果は確かに同じになります。それで、違いは何でしょうか?最も直接的な違いは、subscribe 関数は btn ではなく fromEvent(...) に作用するのに対し、addEventListener は btn に直接作用することです。 subscribe 関数は、ある種の「オープン」操作であり、fromEvent(...) は、ある種のエクスプレス ボックスです。

fromEventは実際にはaddEventListenerへの「遅延」呼び出しです

関数 fromEvent(ターゲット,イベント名){
    関数(コールバック)を返す{
        target.addEventListener(イベント名、コールバック)
    }
}
const ob = fromEvent(btn,"クリック")
ob(console.log) // subscribe と同等

おお! fromEventは本質的には高階関数である

「オープン」操作を完了するためにサブスクライブを実装する方法については、この記事の範囲外です。Rx プログラミングでは、このサブスクライブ アクションは「サブスクリプション」と呼ばれます。 「サブスクリプション」は、すべての Observable の統一された操作です。もう一度言いますが、この記事の Observable への「呼び出し」は論理的には subscribe と同等です。

もう 1 つの例を見てみましょう。基本的に、読者は 2 つの例から N 通りの推論を導き出すことができます。

3.2. エクスプレスボックスモデル2: 間隔

Rx には間隔があります。それと setInterval の違いは何ですか?

すでに誰かが答え始めていると思いますが、interval は setInterval への遅延呼び出しです。ビンゴ!

関数間隔(期間){
    i = 0とする
    関数(コールバック)を返す{
        setInterval(period,()=>callback(i++))
    }
}
定数ob = 間隔(1000)
ob(console.log) // subscribe と同等

上記の 2 つの例から、fromEvent(...) にしろ Interval(...) にしろ、内部ロジックはまったく異なりますが、どちらも「エクスプレス ボックス」と同じものに属しており、これを Observable と呼びます。

fromEvent と Interval は、「エクスプレス ボックス」を作成するためのモデルにすぎません。呼び出し後に返されるのは「エクスプレス ボックス」のみです。つまり、fromEvent(btn,"click")、interval(1000) などです。

4. 高級エクスプレスボックス

上記の基礎を踏まえて、前進を始めましょう。これで、エクスプレスボックスが大量に揃ったので、再梱包することができます。

冒頭でも述べたように、エクスプレスボックスはいくつかの操作を統合しているため、多くのエクスプレスボックスを積み重ねて大きなエクスプレスボックスを形成することができます。この大きなエクスプレス ボックスには、小さなエクスプレス ボックスと同じ「開く」操作 (つまり、サブスクライブ) があります。この大きな宅配ボックスを開けると何が起こるのでしょうか?

小さな箱を一つずつ開ける(連結)、すべての小さな箱を一度に開ける(マージ)、開けやすい箱だけを開ける(競争)など、さまざまな可能性があります。

マージ メソッドの簡略化されたバージョンを次に示します。

関数 merge(...obs){
    関数(コールバック)を返す{
        obs.forEach(ob=>ob(callback)) // すべてのエクスプレスボックスを開く}
}

先ほどの fromEvent と interval を例に挙げてみましょう。

2 つの Observable を結合するには、 merge メソッドを使用します。

const ob1 = fromEvent(btn,'click') // エクスプレスボックス1を作成する
const ob2 = interval(1000) // エクスプレスボックス2を作成する
const ob = merge(ob1,ob2) //大きなエクスプレスボックスを作成する ob(console.log) //大きなエクスプレスボックスを開く

大きなエクスプレス ボックス ob を「開く」(サブスクライブする) と、2 つの小さなエクスプレス ボックスも「開く」(サブスクライブする) ようになり、小さなエクスプレス ボックス内のロジックが実行されます。2 つの Observable を 1 つにマージします。

これが、さまざまな非同期関数を Observable にカプセル化して、それらの操作を統一的に行えるようにするために私たちが一生懸命取り組んでいる理由です。もちろん、単に「開く」(購読する)というのは最も基本的な機能であり、これから高度な機能へと進んでいきます。

5.宅配ボックスを破壊する

5.1. 宅配ボックスを破棄する - 定期購読をキャンセルする

fromEvent を例に挙げてみましょう。以前、addEventListener のラッパーとして単純な高階関数を作成しました。

関数 fromEvent(ターゲット,イベント名){
    関数(コールバック)を返す{
        target.addEventListener(イベント名、コールバック)
    }
}

この関数を呼び出すと、配達ボックスが生成されます (fromEvent(btn,'click'))。この関数によって返された関数を呼び出すと、エクスプレス ボックスが開きます (fromEvent(btn,'click')(console.log))。

では、この開封済みの宅配ボックスをどうやって破棄するのでしょうか?

まず、開いた宅配ボックスを取得する必要があります。上記の関数呼び出しの結果は void であり、これを使用して何もできないため、開いた宅配ボックスを構築する必要があります。高階関数の考え方を引き続き使用します。つまり、破棄操作のために返された関数内で別の関数を返します。

関数 fromEvent(ターゲット,イベント名){
    関数(コールバック)を返す{
        target.addEventListener(イベント名、コールバック)
        関数()を返す{
            target.removeEventListener(イベント名、コールバック)
        }
    }
}
const ob = fromEvent(btn,'click') // 宅配ボックスを作成する const sub = ob(console.log) // 宅配ボックスを開き、それを破棄するために使用できる関数を取得する sub() // 宅配ボックスを破棄する

同様に、間隔についても同じことができます。

関数間隔(期間){
    i = 0とする
    関数(コールバック)を返す{
        id = setInterval(period,()=>callback(i++)) とします。
        関数()を返す{
            クリア間隔(id)
        }
    }
}
const ob = interval(1000) // 宅配ボックスを作成する const sub = ob(console.log) // 宅配ボックスを開く sub() // 宅配ボックスを破棄する

5.2. 高級宅配ボックスを破壊する

マージを例に挙げてみましょう。

関数 merge(...obs){
    関数(コールバック)を返す{
        const subs = obs.map(ob=>ob(callback)) // すべてを購読し、すべての破壊関数を収集します return function(){
            subs.forEach(sub=>sub()) // 破棄関数を走査して実行する}
    }
}
 
const ob1 = fromEvent(btn,'click') // エクスプレスボックス1を作成する
const ob2 = interval(1000) // エクスプレスボックス2を作成する
const ob = merge(ob1,ob2) // 大きなエクスプレスボックスを作成する const sub = ob(console.log) // 大きなエクスプレスボックスを開く sub() // 大きなエクスプレスボックスを破棄する

大型宅配ボックスを破棄する際、中の小型宅配ボックスもすべて一緒に破棄させていただきます。

6. 補足

ここまでで、Observable の 2 つの重要な操作 (サブスクリプションとサブスクリプション解除) について説明しました。サブスクリプション解除の動作は Observable ではなく、「開かれた」エクスプレス ボックス (Observable にサブスクライブした後に返されるもの) に対して実行されることに注意してください。

これに加えて、Observable には、イベントの発行と完了/例外という 2 つの重要な操作があります (これら 2 つの操作は Observable によって開始されるコールバックであり、操作の反対方向であるため、操作と呼ぶことはできません)。

Express Box では、これら 2 つの動作はそれほど鮮明ではありません。Observable は蛇口に例えることができます。Express Box の本来のオープンは蛇口をオンにすることになり、渡されたコールバック関数は水を集めるカップに例えることができます。コールバック関数についてはすでによく知られているため、この記事では詳細には触れません。

VII. 追記

学んだことをまとめると、高階関数を通じていくつかの操作を「遅延」し、統一された動作を与えました。たとえば、「subscribe」は非同期関数の実行を遅延し、「unsubscribe」は上記に基づいてリソース破棄関数の実行を遅延します。

これらのいわゆる「遅延」実行は、理解するのが最も難しく、舞台裏で Rx プログラミングの最も重要な部分です。 Rx の本質は、非同期関数をカプセル化し、それをサブスクリプション、サブスクリプション解除、イベント発行、完了/例外という 4 つの主要な動作に抽象化することです。

Rxライブラリを実際に実装する方法はたくさんあります。この記事では、Observableの本質を誰もが理解できるように、高階関数の考え方のみを使用します。正式版では、Observableボックスは高階関数ではなくオブジェクトですが、本質的には同じです。

上記は、Rx レスポンシブ プログラミングの詳細についての簡単な説明です。Rx レスポンシブ プログラミングの詳細については、123WORDPRESS.COM の他の関連記事をご覧ください。

以下もご興味があるかもしれません:
  • TypeScriptでのRxJSの簡単な使い方の詳しい説明
  • RxJava でサブスクリプションをキャンセルするさまざまな方法を実装する
  • RxJava2 の例外と処理方法について話す
  • RxJS JavaScriptフレームワークCycle.jsを学ぶ
  • RxJS 入門と予備的なアプリケーション
  • このキーがないために RxJava に慣れていない (推奨)
  • RxJava2 スレッドスケジューリング方法
  • RxJava メッセージ送信とスレッド切り替えの実装原理
  • RxJava2 と Retrofit2 のカプセル化チュートリアル (わかりやすく、シンプルで実用的)

<<:  InnoDB テーブルの BLOB 列と TEXT 列のストレージ効率を最適化します。

>>:  Centos8で静的IPを設定する方法の詳細な説明

推薦する

フォーム入力ボックスに関するWebデザインのヒント

1. キャンセル ボタンが押されたときの破線ボックス<br /> 入力に属性値 hide...

Windows10 での MySQL msi インストール チュートリアル (画像とテキスト付き)

1. ダウンロード1. MySQL msi 公式 Web サイトから最新のダウンロードをクリックす...

MySQLの自動増分IDについて知っておくべきこと

はじめに: MySQL を使用してテーブルを作成する場合、通常は自動インクリメント フィールド (A...

HTML テーブルタグチュートリアル (8): 背景画像属性 BACKGROUND

テーブルの背景画像を設定します。任意の GIF または JPEG 画像ファイルを使用できます。基本的...

SSH接続を介してXshellを使用したUbuntu 20.04で報告されたサービス問題の詳細な説明

1. 最近、Ubuntu の新しいバージョンをインストールしました。/etc/ssh/sshd_co...

MySQLの共同クエリ最適化メカニズムの詳細な説明

目次MySQL フェデレーテッド クエリ実行戦略。実行計画フェデレーテッドクエリオプティマイザーMy...

JenkinsのLinuxインストール手順と各種問題解決(ページアクセス初期化パスワード)

1. Java環境jdk1.8を準備するJavaがインストールされているかどうかを確認します。イン...

JavaScriptの動作原理を理解しましょう

目次ブラウザカーネルJavaScript エンジンV8エンジンJavaScript がどのように実行...

JavaScript と CSS を最適化してウェブサイトのパフォーマンスを向上させる

<br /> 第 1 部と第 2 部では、Web サイトのパフォーマンス、ページ コンテ...

WindowsでMysql5.7.17のインストールと起動に失敗する問題を解決する

マシンに初めて MySQL をインストールします。オペレーティングシステムはwin7ですmysqlの...

nginx のフロントエンドとバックエンドに同じドメイン名を設定する方法

この記事では、主にnginxのフロントエンドとバックエンドに同じドメイン名を設定する方法を紹介し、皆...

Swiper.jsプラグインを使用すると、カルーセル画像を非常に簡単に実装できます。

Swiper は、携帯電話やタブレットなどのモバイル端末向けに設計された、純粋な JavaScri...

シンプルなスネークゲームを実現するネイティブjs

この記事では、スネークゲームを実装するためのjsの具体的なコードを参考までに共有します。具体的な内容...

JavaScript スネーク実装コード

この記事の例では、参考までに貪欲なスネークを実装するためのJavaScriptの具体的なコードを共有...