我正在实现一个基于JavaScript的Vaadin组件,需要显示和更新相对较大的数据集。我这样做是通过扩展AbstractJavaScriptComponent
。
我试图让JS方面尽可能“愚蠢”,使用RPC将用户交互委托给服务器,并更新共享状态。然后使用新状态调用JS连接器包装器的onStateChange
函数,这会导致DOM相应地更新。
我有两个问题:
我可以通过保持先前状态并比较其中的部分来找出第二个问题,以找出发生了什么变化,并且只进行必要的DOM更改。 但这仍然是第一个问题。
我是否必须停止使用Vaadin的共享状态机制,而只使用RPC来将更改传达给状态?
更新: 我一直在做一些测试,看来Vaadin的共享状态机制在效率方面很糟糕:
只要组件调用getState()
以更新状态对象中的某些属性(甚至不更新任何内容),就会传输整个状态对象。据我所知,避免这种情况的唯一方法是不使用共享状态机制,而是使用RPC调用将特定状态更改传达给客户端。
RPC方法存在一些需要解决的问题,例如:如果在单个请求/响应周期内多次更改值,则不希望多次进行RPC调用。相反,您只希望发送最后一个值,就像共享状态机制仅在响应中发送最终状态一样。您可以为要分别发送的状态的每个部分保留脏标志(或者只保留先前状态的副本并进行比较),但是您需要在请求处理结束时以某种方式触发RPC调用。怎么办呢?
欢迎提出任何想法!
更新2 :
Vaadin 8修复了根问题:它只发送已更改的状态属性。此外,当仅执行RPC调用(并且不更改任何状态)时,它不再在JS连接器上调用onStateChange()
。
答案 0 :(得分:2)
OP说明共享状态同步对于基于AbstractJavaScriptComponent
的组件来说效率低是正确的。整个状态对象被序列化,只要连接器被标记为脏,就可以使用Javascript连接器的onStateChange
方法。其他非JavaScript组件仅通过发送更改来更智能地处理状态更新。发生这种情况的代码中的确切位置是com.vaadin.server.LegacyCommunicationManager.java
boolean supportsDiffState = !JavaScriptConnectorState.class
.isAssignableFrom(stateType);
我不确定为什么基于AbstractJavaScriptComponent
的组件对状态更新的处理方式不同。也许是为了简化javascript连接器并且不需要从增量组装完整的状态对象。如果可以在将来的版本中解决这个问题,那就太棒了。
如您所知,您可以完全免除JavaScriptComponentState
并依赖服务器>客户端RPC进行更新。在服务器端组件中保留脏标志,或者通过任何所需的机制比较旧状态和新状态。
要合并更改并仅为每次更改发送一个RPC调用,您可以覆盖服务器端组件中的beforeClientResponse(boolean initial)
。这是在向客户端发送响应之前调用的,您可以添加一组RPC调用来更新客户端组件。
或者,您可以覆盖encodeState
,您可以在其中自由发送任何您喜欢的JSON到客户端。您可以选择向super.encodeSate
返回的基本JSON对象添加更改列表。您的javascript连接器可以在其onStateChange
方法中进行适当的解释。
编辑添加:在服务器端组件中调用getState()
会将连接器标记为脏。如果您想获得状态而不将其标记为脏,请改用getState(false)
。
答案 1 :(得分:0)
在我们讨论了这个之后,我为AbstractJavaScriptComponent创建了一个替代品,它可以传输状态增量并包含一些额外的增强功能。它处于早期阶段但应该有用。
https://github.com/emuanalytics/vaadin-enhancedjavascript
解决方案看似简单:基本上绕过com.vaadin.server.LegacyCommunicationManager.java
中的这行代码重新启用状态差异计算:
boolean supportsDiffState = !JavaScriptConnectorState.class
.isAssignableFrom(stateType);
由于Vaadin类不容易扩展所以我不得不复制并重新实现6个类,因此解决方案的实现变得复杂。
答案 2 :(得分:-1)
Vaadin的共享状态与您想要的开箱即用:当第一次将组件添加到DOM时,整个共享状态从服务器传输到客户端,以便它可以实现显示组件。之后,仅传输更改。例如,通过调用component.setCaption("new caption")
来更改可见组件的标题,Vaadin仅将新标题文本传输到客户端并且"合并"那个组件的客户端共享状态实例。