在大型产品中使用“大部分拉动”方法的一些经验:
模型:节点构建一个 1:N 树,即每个组件(根除外)有 1 个父级和 1..N 个子级。数据几乎完全从父母流向孩子。更改通知可以来自树中的任何节点。
实现:通过发送节点的 id 和“生成”计数器通知所有叶子。叶子知道它们依赖于哪个节点路径,因此它们知道是否需要更新。(任何其他子节点更新算法也可以,事后看来可能会更好)。
Leafs 向其父级查询当前数据,递归地查询冒泡。包括生成计数器,因此冒泡在始发节点处停止。
好处:
- 父节点不需要太多/任何关于其子节点的信息。任何人都可以使用数据——这允许一种通用方法在用于显示的数据之上实现一些(最初不是预期的)非 UI 功能
- 子节点可以聚合和延迟更新(避免重绘肯定胜过快速绘制)
- 不活动的叶子确实不会导致任何数据流量
缺点:
- 由于发布了完整的数据,增量更新的成本很高。该实现实际上允许请求不同的数据包(并且生成计数器可以防止不必要的数据流量),但最初设计的数据包非常大。切片它们是事后的想法,但工作正常。
- 你需要一个真正好的生成机制。最初实现的与初始更新(需要特殊处理 - 请参阅“增量更新”)和更新聚合相冲突
- 数据在树上传播的需求被大大低估了。
- 只有当节点提供对当前数据的只读访问时,发布才便宜。不过,这可能需要额外的更新同步
- 有时您希望中间节点更新,即使所有叶子都处于非活动状态
- 一些叶子最终实现了轮询,一些基本节点最终依赖于此。丑陋。
一般来说:
当数据和处理层对 UI 一无所知时,Data-Pull 对我来说“感觉”更加原生。但是,它需要复杂的更改通知机制来避免“更新宇宙”。
Data-Push 简化了增量更新,但前提是发送者非常了解接收者。
我没有使用其他模型的类似规模的经验,所以我无法真正提出建议。回想起来,我发现我大部分时间都在使用 pull,这不那么麻烦。看看其他人的经历会很有趣。