web-dev-qa-db-ja.com

進行状況をUIに報告するための最善の戦略-コールバックはどのように行うべきですか?

ユーザーは、実行に時間がかかる拡張技術操作を開始することがあります。このような場合、通常、現在進行中のタスクに関する情報とともに、ある種の進行状況バーを表示すると便利です。

UIとロジックレイヤーの密接な結合を回避するために、通常、ある種のプロキシを介して通信を行うのが最善です。つまり、バックエンドが独自のUI要素を操作したり、中間層と直接対話したりすることはできません。

明らかに、これを機能させるには、どこかにコールバックが必要です。私は通常、次の2つの方法のいずれかで実装しました。

  1. 変更可能なオブジェクトをバックエンドに渡し、進行中にバックエンドに変更を加えます。オブジェクトは、変更が発生したときにフロントエンドに通知します。

  2. バックエンドが呼び出すvoid f(ProgressObject)またはProgressObject -> unitの形式のコールバック関数を渡します。この場合、バックエンドはProgressObjectを構築し、完全にパッシブです。進捗状況を報告するたびに、新しいオブジェクトを作成する必要があると思います。

これらの方法の欠点と利点は何ですか?使用するのに合意された最良の方法はありますか?それらを使用するためのさまざまな状況はありますか?

私が見落とした、進捗状況を報告するまったく異なるテクニックはありますか?

11
GregRos

変更可能なオブジェクトをバックエンドに渡し、進行中にバックエンドに変更を加えさせます。オブジェクトは、変更が発生したときにフロントエンドに通知します。

この点でバックエンドが通知する場合、効率のバランスをとることは困難です。非常にスムーズな進行状況の更新を目的としている場合、注意を怠ると、進行状況を増分すると、操作の完了にかかる時間が2倍または3倍になることに気付く場合があります。

Void f(ProgressObject)またはProgressObject-> unitという形式のコールバック関数を、バックエンドが呼び出すユニットに渡します。この場合、バックエンドはProgressObjectを構築し、完全にパッシブです。 。進捗状況を報告するたびに、新しいオブジェクトを作成する必要があると思います。

ここではあまり違いはありません。

私が見落とした、進捗状況を報告するまったく異なるテクニックはありますか?

フロントエンドから別のスレッドでポーリングし、バックエンドでアトミックな増分を行います。ポーリングは有限の期間で終了する操作のためであり、フロントエンドが状態変化を取得する可能性が高いため、ここではポーリングが意味をなしています。フロントエンドスレッドからのポーリングのアイデアが気に入らない場合は、条件変数を検討できますが、その場合は、細かいプログレスバーの増分ごとに通知しないようにすることができます。

8
user204677

これがPushpullの通知メカニズムの違いです。

変更可能なオブジェクト(pull)は、バックエンドタスクがバックグラウンド/ワーカースレッドで実行されることが予想される場合、UIによって繰り返しポーリングされ、同期される必要があります。

コールバック(Push)は、何かが実際に変更されたときにのみUIの作業を作成します。多くのUIフレームワークには、ワーカースレッドから呼び出し可能なinvokeOnUIThreadもあり、UIスレッドでコードの一部を実行できるため、スレッド関連の危険に踏み込むことなく実際に変更を加えることができます。 (しゃれ意図)

一般的にPush通知は、作業を行う必要がある場合にのみ機能するため、推奨されます。

2
ratchet freak

「2つの方法」は別の概念であるかのように説明されていますが、少しお返ししたいと思います。

  1. 変更可能なオブジェクトをバックエンドに渡し、進行中にバックエンドに変更を加えます。オブジェクトは、変更が発生したときにフロントエンドに通知します。

UIとロジックのクローズカップリングを回避する必要があると既に述べたので、渡す "可変オブジェクト"は実際にはロジックモジュールで定義されている特定のインターフェイスの実装であると考えることができます。そのため、これは、進行状況に関する情報を定期的に呼び出すプロセスにコールバックを渡すもう1つの方法にすぎません。

メリットとデメリットは...

メソッド(1)の欠点は、インターフェイスを実装するクラスが一度しか実行できないことです。 (異なる呼び出しで異なるジョブを実行する場合は、switchステートメントまたはビジターパターンが必要になります。)メソッド(2)を使用すると、同じオブジェクトは、バックエンドコードの呼び出しごとに異なるコールバックを使用できます。スイッチ。

メソッド(1)の長所は、メソッド(2)の複数のコールバックや、複数のコンテキストのswitchステートメントを使用した単一のコールバックを処理するよりも、インターフェイスに複数のメソッドを置く方がはるかに簡単なことです。

0
Daniel T.

AngularJSでwebsocketを使用しています。フロントエンドがメッセージを受信すると、指定されたメッセージ領域に表示され、数秒後に空白になります。バックエンドでは、ステータスメッセージをメッセージキューにポストするだけです。テキストのみを送信しますが、完了率や転送速度などの値を持つステータスオブジェクトを送信できなかった理由はありません。

0
TMN