Vue和Rax都是Weex内置的js前端框架,最近花了点调研了下。关于Vue和Rax的详细原理这里就不赘述了,有兴趣的同学可以直接从官网下载源码或者通过其他资料来分析,这里主要和大家分享下我个人对Vue和Rax的理解。
一、先说说Rax和Vue
首先来看看它们的原理和区别。
1、设计理念
Vue定位于构建用户界面的渐进式框架,“渐进式”是设计的“指导思想“,核心库只解决界面构建的问题,而对于比较复杂的需求比如单页应用等,可以采用Vue-Router、Vuex等扩展框架来搭建。
Rax是基于React标准的跨容器解决方案,用成熟的React的语法标准,实现能在Weex,Web,WebGL等多种容器上渲染。它设计的核心思想是“React标准”和“跨容器”。
2、实现机制
Vue采用了MVVM模式,实现思路是数据绑定,数据的变更通过观察者模式反应到虚拟dom上。Vue在开发时将结构、表现、行为分得很清晰,算是一套相对完善的UI层开发模式,大部分情况下不需要单独做抽离了。不过也是由于绑定机制,Vue在变更数组数据、动态添加绑定对象属性时需要用特殊处理方式。
而Rax实现的思路是单向数据流,数据驱动UI渲染,数据变化了,可以直接通知dom更新。在写法上,视图和业务逻辑耦合在一起,如果业务逻辑比较复杂,可能需要单独抽一层处理业务逻辑,当然,这个问题也是仁者见仁、智者见智了。
两者都实现了虚拟dom,采用逐层比较的方式,复杂度O(n)。针对虚拟dom的遍历都有一些优化措施,比如列表采用key、组件拆分局部更新等等。
Vue采用了异步渲染,当前runloop的更新变化均放到一个队列里,再下一个runloop做统一更新。而Rax的setState是同步的,开发者需要自己控制好更新时机,否则可能导致性能问题,这是一个需要注意的点。
Vue和Rax组件通信方式类似,父组件可以通过props给子组件传递数据,子组件可以通过callback的方式调用父组件。当然了,你也可以拿到子组件或者父组件的实例直接调用相应的方法。对于兄弟组件或者跨层组件,可以通过发事件的方式通信,也可以单独引入状态管理框架来处理。
3、社区生态
Rax基于React标准,React的进入比较早,社区活跃度高,爱好者也比较多,有Facebook的团队来维护,认可度也比较高。Vue经过这两年的快速增长,社区也是很活跃的,如今有了专门的团队来维护,相信未来的发展也是不错的。我对Vue和React的社区了解不是特别深,这里就不做过多评论了。
二、性能优化
我一直认为,衡量对一个框架掌握程度最简单的办法就是能不能基于这个框架在复杂需求场景下进行有效的性能优化。如果要做性能优化,肯定得对这个框架有充分的理解才行;你说你对这个框架掌握很充分了,但是遇到点性能问题就没办法解决了,那说不过去。
1、Vue
(1)尽量减少watcher的数量。
这个比较好理解,减少watcher数量能减少内存占用,减少数据更新响应时间。可以采取的方法比如适当利用v-once和Object.freeze。v-once只在初始化时渲染一次,Object.freeze可以取消绑定,两者区别主要是v-once是针对dom的,而Object.freeze是针对数据的。再比如用watch绑定属性监听的时候慎用deep=true,这会导致递归遍历,除非你明确知道你是需要这样做的。
(2)将复杂组件合理拆分成更小粒度的组件
这样做的好处是做局部更新,减少数据更新时的性能损耗。在Vue的更新逻辑里,如果当前组件的数据更新了,一般只需要更新当前组件和子组件,而不会更新父组件和兄弟组件。比如一个长列表,如果直接在父层级展开,每次子项更新的触发都会可能导致整个列表的再次遍历。
(3)子组件适当提供key
这和虚拟dom的patch机制有关,给子组件提供key能减少在子组件插入、删除和移动时的性能损耗。
(4)长列表适当分页
这样可以减少每次渲染的数据量。长列表也是比较容易遇到性能问题的,上面说的几个优化点其实都可以应用在长列表。
2、Rax
(1)利用shouldComponentUpdate,PureComponent,StatelessComponent优化组件渲染
这个可能就很常见了,也很好理解。shouldComponentUpdate将更新的决定权交给开发者,PureComponent在更新触发时会比较props和state,如果没变化就不更新了。StatelessComponent在组件渲染时不会生成Component实例,能减少一定性能开销。
(2)尽量自己来控制dom的更新时机
Rax的setState是同步的,要避免频繁调用,最好是数据都统一更新,自己手动调用forceUpdate更新dom。
(3)子组件适当提供key,尽量保持组件dom结构的稳定
子组件设置key这个点和Vue原理是类似的,保持dom结构稳定也和虚拟dom的diff机制有关,可以避免频繁的创建和删除大块的dom节点。
(4)适当使用immutable.js
关于immutable.js的详细介绍和对性能的优化可以参考这里。
当然了,类似长列表分页、复杂组件合理拆分成更小粒度的组件也有利于减少性能开销。Rax把很多处理性能优化的工作交给了开发者来处理,这也是Rax对开发人员要求更高的一个原因。
上面这些优化点大多是从框架本身运行机制出发的,除此之外,还可以结合具体的业务场景来针对性的优化。其实很多时候,代码设计上小小的改进往往能带来很大的性能提升,这些都需要我们对框架的运行机制有充分的掌握。
三、如何选择好呢
Vue的template、script、style是分离的,可读性和可维护性比较好,你可以构建非常复杂的模版但是不会影响对业务逻辑的关注,这对一些经验水平参差不一的团队有助于保持规范统一。
Rax重点还是只关注UI层,视图和业务逻辑是混合在一起的,甚至style也是采用css-in-js的方式,所以对开发者的要求会高一些,如果没有一定的经验和规范约束,很容易导致项目臃肿、结构混乱的问题。
目前在移动端React和Vue都有很高的占比,同时增长势头也都不错,社区生态也都比较活跃。个人觉得没必要过于纠结哪个框架更好或者前景更好,具体的选型可以结合团队的实际情况来选择,比如团队本身是基于类React框架的,选择Rax就顺理成章了;如果是像我们这样本来是客户端团队,比较熟悉MVVM,那选择Vue有利于保持开发模式的统一。其实不管是选择哪一类作为主要技术栈,另外一类框架也都可以在一些项目中尝试。
在使用上应该注意解耦,减少侵入性,怎么说?Vue和Rax本质上还只是属于UI层模式,在接入时应该注意和自己的底层框架解耦,比如一些基础库,登录、网络等等。或者如果有类似游戏这样的场景,很多情况下游戏的完成需要游戏引擎和UI框架来共同完成,比如游戏主体使用游戏引擎开发,而某些页面可能需要用Vue/Rax这类框架,这时就应该注意两类框架的边界。保证一个框架的升级,甚至是切换到其他框架尽量不受另外一个框架的影响。尤其是前端框架本身就变化比较快。
无论选择哪个框架,都应该认真研究下框架原理,能够掌握其运行机制,对框架各自的优缺点和可能潜在的问题做到心里有数,这样在应对一些复杂的需求时才能游刃有余。
当然了,如果团队有实力又有资源,自己做个框架也是未尝不可的。毕竟,Rax不也是一个轮子么,关键是有没有符合公司的业务场景,能不能给业务的带来价值。