本系列的上一篇文章《React.Component损害了复用性?》探讨了如何在前端开发中编写可复用的界面元素。本篇文章将从性能和算法的角度比较 Binding.scala 和其他框架的渲染机制。 Binding.scala 实现了一套精确数据绑定机制,通过在模板中使用 bind 和 for/yield 来渲染页面。你可能用过一些其他 Web 框架,大多使用脏检查或者虚拟 DOM 机制。和它们相比,atv,Binding.scala 的精确数据绑定机制使用更简单、代码更健壮、性能更高。 ReactJS虚拟DOM的缺点 比如, ReactJS 使用虚拟 DOM 机制,让前端开发者为每个组件提供一个 render 函数。render 函数把 props 和 state 转换成 ReactJS 的虚拟 DOM,然后 ReactJS 框架根据 render 返回的虚拟 DOM 创建相同结构的真实 DOM。 每当 state 更改时,ReactJS 框架重新调用 render 函数,获取新的虚拟 DOM 。然后,框架会比较上次生成的虚拟 DOM 和新的虚拟 DOM 有哪些差异,进而把差异应用到真实 DOM 上。 这样做有两大缺点: 每次 state 更改,render 函数都要生成完整的虚拟 DOM,哪怕 state 改动很小,render函数也会完整计算一遍。如果 render 函数很复杂,这个过程就会白白浪费很多计算资源。 ReactJS 框架比较虚拟 DOM 差异的过程,既慢又容易出错。比如,你想要在某个 <ul> 列表的顶部插入一项 <li> ,那么 ReactJS 框架会误以为你修改了 <ul> 的每一项 <li>,然后在尾部插入了一个 <li>。 这是因为 ReactJS 收到的新旧两个虚拟 DOM 之间相互独立,ReactJS 并不知道数据源发生了什么操作,atv,只能根据新旧两个虚拟 DOM 来猜测需要执行的操作。自动的猜测算法既不准又慢,必须要前端开发者手动提供 key 属性、shouldComponentUpdate 方法、componentDidUpdate 方法或者 componentWillUpdate 等方法才能帮助 ReactJS 框架猜对。 AngularJS的脏检查 除了类似 ReactJS 的虚拟 DOM 机制,其他流行的框架,比如 AngularJS 还会使用脏检查算法来渲染页面。 类似 AngularJS 的脏检查算法和 ReactJS 有一样的缺点,无法得知状态修改的意图,必须完整重新计算 View 模板。除此之外,AngularJS 更新 DOM 的范围往往会比实际所需大得多,所以会比 ReactJS 还要慢。 Binding.scala的精确数据绑定 Binding.scala 使用精确数据绑定算法来渲染 DOM 。 在 Binding.scala 中,你可以用 @dom 注解声明数据绑定表达式。@dom 会自动把 = 之后的代码包装成 Binding 类型。 比如: @domvali:Binding[ Int] = 1@domdeff:Binding[ Int] = 100@domvals:Binding[ String] = "content" @dom 既可用于 val 也可以用于 def ,可以表达包括 Int 、 String 在内的任何数据类型。 除此之外,@dom 方法还可以直接编写 XHTML,比如: @domvalcomment:Binding[ Comment] = <!-- Thisis a HTMLComment--> @domvalbr:Binding[ HTMLBRElement] = <br/> @domvalseq:Binding[ BindingSeq[ HTMLBRElement]] = <br/><br/> 这些 XHTML 生成的 Comment和 HTMLBRElement是 HTML Node的派生类。而不是 XML Node。 每个 @dom 方法都可以依赖其他数据绑定表达式: vali:Var[ Int] = Var( 0) @domvalj:Binding[ Int] = 2@domvalk:Binding[ Int] = i.bind * j.bind @domvaldiv:Binding[ HTMLDivElement] = <div>{ k.bind.toString }</div> 通过这种方式,你可以编写 XHTML 模板把数据源映射为 XHTML 页面。这种精确的映射关系,描述了数据之间的关系,而不是 ReactJS 的 render 函数那样描述运算过程。所以当数据发生改变时,只有受影响的部分代码才会重新计算,而不需要重新计算整个 @dom 方法。 比如: (责任编辑:本港台直播) |