如何看待 snabbdom 的作者开发的前端框架 Turbine 抛弃了虚拟DOM?

snabbdom (vue.js / cycle.js 的 virtual dom 都用了 snabbdom) 的作者自己写了个 FRP 的前端框架,该框架不仅不用虚拟DOM (以及snabbdom),还称当前的大多数 FRP以及基于观察者模式的框架在虚拟DOM的使用上存在问题。参考作者的说明:Why Turbine doesn't use virtual DOM · Issue #32 · funkia/turbine
关注者
908
被浏览
54169

大致的理解:在整体使用 FRP 的前提下,Cycle.js 是这样的:

Multiple state streams => merged into single state stream => vdom stream => diff

经过了一个从分散的状态流,合并成一个状态流,映射到 vdom 流,最后 diff 的过程。

这里的问题是在状态流合并的过程中,丢弃了各个状态流和 DOM 元素之间的关系。这个关系在 diff 的时候又被重新暴力计算了一遍,所以有浪费。Turbine 的策略是不合并状态流,直接映射到 DOM 副作用。

这和 Vue 1 的针对每个绑定单独观察的策略其实有些类似。需要顾虑的是在可能变动的 DOM 节点比较多的时候,大量对应的 watcher / observer 的常驻内存占用。另外这样的策略必须是基于 fine-grained + push-based 的响应机制,框架不是基于这样的前提去设计的话,还是得用 vdom,除非像 svelte 那样直接把副作用在编译的时候就编译好。

作者的那段话并不是在说『vdom 是错误的方向』,而是说『在 FRP 的前提下,vdom 不是性能最优的选择』。

我对这个策略的顾虑:

- 抛弃状态流的合并这一步,会不会导致 debug 方面的难度,因为这样就没有一个统一的入口去获得某一时间点的状态快照。

- vdom 的一个好处就是它把最终的副作用和应用的『视图状态』隔离了。这个策略等于从『数据状态』直接映射到『副作用』,完全丢掉了『视图状态』这个中间步骤。这样的话对于做非 DOM 的渲染可能会增加难度,但是如果把副作用层设计成抽象的接口,应该也可以做。

- 开发体验上,vdom 的渲染函数是一个同步的纯函数,Turbine 的 view 函数貌似还带各种 yield,感觉这个一般开发者还是挺难适应的...

总的来说这还是一个比较底层的实现/性能细节。与其关注 vdom,还不如关注 Turbine 和 Cycle 之间的异同。这个问题其实应该找 Andre Staltz 来答...