web-dev-qa-db-ja.com

core.asyncと関数型反応型プログラミング(+ Rx)の比較

Clojureのcore.asyncをいわゆるReactive Extensions(Rx)および[〜#〜] frp [〜と比較すると、少し混乱しているようです。 #〜]一般に。彼らは非同期調和の同様の問題に取り組んでいるように見えるので、私は主な違いは何であり、どの場合に他が優先されるのか疑問に思います。誰かが説明できますか?

編集:より詳細な回答を促すために、質問をより具体的にしたいと思います:

  1. Core.asyncを使用すると、同期的に見えるコードを記述できます。しかし、私が理解しているように、FRPは1レベルのネストされたコールバックのみを必要とします(ロジックを処理するすべての関数は、引数としてFRP APIに渡されます)。これは両方のアプローチがコールバックピラミッドを不要にするようです。 JSではfunction() {...}を何度も記述する必要があることは事実ですが、主な問題であるnestedコールバックは、 FRPも。私はそれを正しく理解していますか?

  2. [〜#〜] frp [〜#〜]制御の流れを伴うメッセージの通信を補完します」あなた(誰か)は、より具体的な説明を提供できますか?

  3. チャネルを渡すのと同じ方法でFRPの監視可能なエンドポイントを渡すことはできませんか?

一般的に私は両方のアプローチが歴史的にどこから来たのかを理解しており、両方でいくつかのチュートリアルを試しました。しかし、私は違いの自明ではないことに「麻痺」しているようです。いくつかありますこれらの1つで書くのが難しく、もう1つを使用して簡単にできるコードの例?そして、その建築上の理由は何ですか?

59
tillda

非同期性「問題」に取り組んでいる人はいないので、主な問題は、取り組んだ問題についてのあなたの仮定がそうではないことだと思います。

抽象化

FRP主なアイデアは変更の伝播です。Excelが行うのと同じことを考えて、セルをcascadeで相互に依存して定義し、1つのセルが変更すると、カスケード上のすべての依存セルが再計算されます。

core.async主なアイデアはシステムの分解です。異なるプロセスの真ん中でqueueを使用して問題を分離すると考えてください。core.asyncの場合、キューの代わりにチャネルがありますが、アイデアは得られます。

したがって、ピラミッドコードを削除することはどちらのテクノロジーの目的でもなく、異なる抽象化レイヤーで動作します。

制御フローの補完について

通信とフロー制御の強化に関するアイデアは、 元のコア非同期ポスト から引用されたものです。

イベント/コールバックをよりクリーンにするさまざまなメカニズム(FRP、Rx/Observables)がありますが、それらは基本的な性質を変更しません。つまり、イベントが発生すると、同じスレッドで他のコードが実行され、 「ハンドラーであまり多くの作業を行わない」などの警告、および「コールバック地獄」などのフレーズ。

言い換えると、イベントハンドラ内にビジネスドメインコードがある場合、Xイベント処理Xが発生したときの処理.

真ん中にqueue/channelを導入することでcore.asyncが取り組むのはこれであり、懸念事項をより適切に分離するのに役立ちます。

実装

コールバックとパラメーターとして監視可能なエンドポイントを渡すことに関するすべての質問は、単なる実装の質問であり、実際にはRxの実装とAPIに依存します。

React reusable components を見ると、実際に見られるコールバックの地獄はほとんどなく、オブザーバブルを渡すというアイデアを得ています。

最終的な考え

Rxを使用してデータフローをモデル化できる場合でも、より一般的にはUIレンダリングa-la Excelで使用され、ビューの更新方法を簡素化します。モデルの変更。

一方、Core.Asyncは、任意の2つのサブシステムが相互に通信する場合の懸念の分離をモデル化するために使用でき(キューと同じ使用シナリオ)、UIレンダリングチェーンでそれを使用すると、主に次のようになります。

  • サーバー側イベントの生成と処理
  • そのイベントがモデルに与える影響

したがって、core.asyncFRPを一緒に使用できます。これは、core.asyncが問題を分離し、モデルが更新されるとFRPがカスケードデータフローを定義するためです。

31

主な主な違いの少なくとも1つ、および「[FRP]による制御とフローのメッセージの通信の補完」によるRich mentは次のとおりです。

コールバックは実行されるコードです。そしてその実行は、ある時点であるスレッドで行われなければなりません。多くの場合、時間はイベントが発生したときであり、スレッドはイベントを通知/生成するスレッドです。プロデューサーが代わりにチャネルにメッセージを配置する場合は、必要なときに任意のスレッドでメッセージを自由に消費できます。したがって、本質的に通信の一種であるコールバックは、コールバックコードが実行されるタイミングと場所を指示することにより、制御の流れを伴う通信を補完します。なんらかの理由でコールバックを使用する必要がある場合は、コールバックを使用してメッセージをキュー/チャネルに配置するだけで、軌道に戻ります。

Core.asyncはそれほど複雑ではないので、代替を使用する正当な理由がない限り、推奨されます。

23
oskarkv

Clojure core.asyncはGo言語のgoブロックのポートです 。基本的な概念は、スレッド間の非同期通信を表すチャネルです。

目標は、チャネルにアクセスして入力を取得するシーケンシャルコードの通常のブロックを記述できるようにすることであり、これはシームレスにステートマシンに変換されて [〜#〜] csp [〜#〜] あなたのための翻訳。

根本的にはコールバックに関するFRPとは対照的です。FRPは、メッセージの通信を制御のフローと組み合わせます。 core.asyncはコードからのコールバックを完全に排除し、制御フローをメッセージ送信から分離します。また、FRPではチャネルはファーストクラスオブジェクトではありません(つまり、FRPチャネルの値としてFRPチャネルを送信することはできません)。

11
noisesmith

編集:

あなたの質問に答えるには:

  1. はい、多くの場合、コールバックは、たとえば、再試行ロジック、distinctUntilChanged、および次のような他の多くのものを使用して排除できます。

    var obs = getJSON('story.json').retry(3);

    var obs = Rx.Observable.fromEvent(document, 'keyup').distinctUntilChanged();

  2. フロー制御でそれをより複雑にすることの意味がわかりません。

  3. はい、以下のオブジェクトのように、チャネルのようにオブジェクトを渡すことができます。

たとえば、RxJSに ReplaySubject を使用して、チャネルのような動作をさせることができます。

var channel = new Rx.ReplaySubject();

// Send three observables down the chain to subscribe to
channel.onNext(Rx.Observable.timer(0, 250).map(function () { return 1; }));
channel.onNext(Rx.Observable.timer(0, 1000).map(function () { return 2; }));
channel.onNext(Rx.Observable.timer(0, 1500).map(function () { return 3; }));

// Now pass the channel around anywhere!
processChannel(channel);

もう少し具体的にするには、David Nolenの投稿 here のコードとRxJS FRPの例 here を比較してください。

5

FRPとCSPを限られた一連の例(ただし、CSPの利点を示すことを目的としています)で比較する投稿がここにあります。最後に結論があります。 http://potetm.github.io/2014/ 01/07/frp.html

4
Robert Monfera