2016-03-27 17 views
3

比較的大きなデータセットを表示および更新する必要があるJavaScriptベースのVaadinコンポーネントを実装しています。私はAbstractJavaScriptComponentを拡張してこれをやっています。VaadinのAbstractJavascriptComponentの部分的な状態の変更

私は、RPCを使ってサーバーとユーザーのやりとりを委任し、共有状態を更新するJS側をできるだけ「ダム」に保ちようとしています。 JSコネクタラッパーのonStateChange関数が新しい状態で呼び出されると、それに応じてDOMが更新されます。

私は2つの問題を持っている:

  1. 私は小さな部分が更新されるたびにセット全体のデータを転送する必要はありません。
  2. 私は毎回UIを完全に再構築したくありません。

私は前の状態を維持し、その部分を比較して何が変更されたかを知り、必要なDOMを変更するだけで解決できます。 しかし、それでも最初の問題が残っています。

私はVaadinの共有状態メカニズムの使用をやめ、その変更を状態に伝達するためにRPCを使用するだけですか?

更新: 私はいくつかのテストを行ってきた、そして確かにVaadinの共有状態メカニズムは、効率の面で恐ろしいであることが表示されます:

コンポーネントがでいくつかのプロパティを更新するためにgetState()を呼び出すたび(または何も更新しなくても)状態オブジェクト全体が転送されます。これを避ける唯一の方法は、共有状態メカニズムを使用せず、RPC呼び出しを使用して特定の状態変更をクライアントに伝えることです。

解決方法RPCのアプローチにはいくつかの問題があります。例えば、1回の要求/応答サイクル内で値を複数回変更する場合は、RPC呼び出しを複数回実行する必要はありません。代わりに、共有状態メカニズムが応答内の最終状態のみを送信するように、最後の値だけを送信するだけです。別々に送信したい(または以前の状態のコピーを保持して比較する)状態の各部分に対して汚れたフラグを保持できますが、要求処理の最後に何らかの方法でRPC呼び出しをトリガする必要があります。これはどうすればできますか?

これに関するアイデアは大歓迎です!

アップデート2

Vaadin 8つのフィックス根本問題:それだけで変更された状態のプロパティを送信します。また、RPCコールだけを行うとき(そして状態を変更しないとき)、JSコネクタ上でonStateChange()を呼び出すことはありません。

答えて

2

AbstractJavaScriptComponentベースのコンポーネントでは、共有状態の同期が非効率的であることを示す点で正しいです。コネクターがdirtyとマークされると、状態オブジェクト全体がシリアライズされ、JavascriptコネクターのonStateChangeメソッドで使用可能になります。他のjavascript以外のコンポーネントは、変更を送信するだけで状態の更新をよりインテリジェントに処理します。状態更新がAbstractJavaScriptComponentベースのコンポーネントのために異なる方法で処理され、なぜこの問題が発生したコード内の正確な場所は、私はよく分からないcom.vaadin.server.LegacyCommunicationManager.java

boolean supportsDiffState = !JavaScriptConnectorState.class 
      .isAssignableFrom(stateType); 

にライン97です。たぶんそれはjavascriptコネクタを単純化し、完全な状態オブジェクトをデルタからアセンブルする必要性を取り除くことでしょう。これが将来のバージョンで対処できるならば素晴らしいだろう。

あなたが提案したように、JavaScriptComponentStateを完全に排除し、更新のためにserver-> client RPCに依存することができます。サーバー側のコンポーネントに汚れたフラグを保持したり、必要なメカニズムで古い状態と新しい状態を比較したりしてください。

変更を統合し、変更ごとに1つのRPC呼び出しのみを送信するには、サーバー側コンポーネントでbeforeClientResponse(boolean initial)を上書きできます。これは、クライアントに応答を送信する直前に呼び出され、一連のRPC呼び出しを追加してクライアント側コンポーネントを更新する機会です。

また、encodeStateを無効にして、どこにいても自分の好きなJSONをクライアントに送信することができます。 super.encodeSateによって返されたベースJSONオブジェクトに変更のリストを追加することもできます。あなたのjavascriptコネクタは、onStateChangeメソッドで適切に解釈できます。

編集の追加:サーバー側コンポーネントのgetState()を呼び出すと、コネクタが汚れているとマークされます。汚れているとマークしないで状態を取得する場合は、代わりにgetState(false)を使用してください。

+0

まさに私が探していた答え。 encodeStateをオーバーライドするときに完全な状態を送信しないことで「不正行為」を行っている場合、切り離しや接続に関する警告はありますか?例えば、完全な状態が切り離されて再接続された後に送られるべきであるか? – herman

+0

残念ながら、私は今、答えを受け入れなくてはなりません。その理由は、 'AbstractComponent#beforeClientResponse(boolean initial)'が 'getState()'を繰り返し呼び出すので、フル状態の転送( 'onStateChange()' JS関数の呼び出し)を防ぐことができないためです。汚れた。もちろん、上書きすることはできますが、コードが理由で存在していると確信しています。 IMOこれはVaadinのバグです。 – herman

+0

[このチケット](https://dev.vaadin.com/ticket/19828)を問題追跡担当者に提出しました。私はそれを回避するためにいくつかの方法を見つける必要があります。 – herman

-1

Vaadinの共有状態は、すぐに使用できるように機能します。コンポーネントが初めてDOMに追加されると、共有状態全体がサーバーからクライアントに転送され、コンポーネントを表示することができます。その後、変更のみが転送されます。たとえば、component.setCaption("new caption")を呼び出して可視コンポーネントのキャプションを変更すると、Vaadinはその新しいキャプションテキストをクライアントに転送し、それをコンポーネントのクライアント側共有状態インスタンスに「マージ」します。

+0

ネストされたプロパティが変更された場合、どのように機能しますか?たとえば、私の状態オブジェクトに人のリストがあり、その人のアドレスの1つが変更された場合移転されるもの:リスト全体、単一の人物、または単一の住所ですか? – herman

+0

申し訳ありませんが、downvoteする必要があります。私はこれをテストしました:コンポーネントは 'getState()'を呼び出して、(setCaption()でも)値を更新して、コネクターをダーティとマークさせます。単一の値が変更されました。実際には、何も変更されていなくても( 'getState()'だけが呼び出されます)。 – herman

+0

Hermanは、 'AbstractJavaScriptComponent'ベースのコンポーネントに対して変更検出が実装されていないと述べています。詳細は私の答えを見てください。 –

0

私たちはこのことについて議論した後、状態デルタを送信するAbstractJavaScriptComponentの代わりにドロップインを作成しました。これにはいくつかの拡張機能が含まれています。それは非常に早い段階にありますが、役に立つはずです。

https://github.com/emuanalytics/vaadin-enhancedjavascript

溶液は一見単純である:com.vaadin.server.LegacyCommunicationManager.javaにコード行をバイパスすることにより、基本的に再有効化状態の差の計算:

boolean supportsDiffState = !JavaScriptConnectorState.class 
     .isAssignableFrom(stateType); 

こと溶液の実装は事実によって複雑になりますVaadinクラスは簡単に拡張されないので、6つのクラスをコピーして再実装する必要がありました。

+0

ありがとうございます。私は時間があるときに見てみましょう。 Vaadinのクラスは、私的な/最終的なもののために拡張が困難であることも以前から気づいています。私はまだ、diffアルゴリズムが有効になっていても、JSコネクタラッパーの 'onStateChange()'関数への不要な呼び出しを修正する必要があると考えています。今、私は問題のその部分について、状態に 'version'プロパティーを追加し、実際にはいくつかの状態プロパティーを変更し、それをコネクター・ラッパーの前の値と比較するときにのみ増分することで作業しました。 – herman

+0

Btwでは、共有状態をまったく使用せず、(callFunction'を使用して)JSメソッドを明示的に呼び出して、特定の状態の変更を伝えることが好ましいでしょう( 'beforeClientResponse'の合体を使用して、 )?そうすれば、クライアントはデルタを調べることで何が変わったのか把握する必要もありません。 – herman

+0

このコンポーネントでは、callFunction()を使用してserver-> client RPCを実行するときにonStateChange()は呼び出されません。膨大なペイロードなしで共有状態またはRPCを自由に使用できます。この点で、このコンポーネントを使用することは、 'ネイティブ' vaadin/GWTベースのコンポーネントを使用することとまったく同じです。共有状態を使用するかRPC(またはその両方を使用するか)を使用するかどうかはあなた次第であり、ラッピングしているJavascriptコンポーネントによってどのようなAPIが公開されているかによって異なります。たとえば、APIがフラットな手続き型APIの場合、おそらくRPCがより適しています。私はMapboxGL.jsをラップしてミックスを使用しています。 –

関連する問題