杨博
ThoughtWorks
本文转载自InfoQ:http://www.infoq.com/cn/articles/more-than-react-part03
bind
和 for
/yield
来渲染页面。你可能用过一些其他 Web 框架,大多使用脏检查或者虚拟 DOM 机制。和它们相比,Binding.scala 的精确数据绑定机制使用更简单、代码更健壮、性能更高。1
render
函数。render
函数把 props
和 state
转换成 ReactJS 的虚拟 DOM,然后 ReactJS 框架根据 render
返回的虚拟 DOM 创建相同结构的真实 DOM。state
更改时,ReactJS 框架重新调用 render
函数,获取新的虚拟 DOM 。然后,框架会比较上次生成的虚拟 DOM 和新的虚拟 DOM 有哪些差异,进而把差异应用到真实 DOM 上。state
更改,render
函数都要生成完整的虚拟 DOM,哪怕 state
改动很小,render
函数也会完整计算一遍。如果 render
函数很复杂,这个过程就会白白浪费很多计算资源。<ul>
列表的顶部插入一项 <li>
,那么 ReactJS 框架会误以为你修改了 <ul>
的每一项 <li>
,然后在尾部插入了一个 <li>
。这是因为 ReactJS 收到的新旧两个虚拟 DOM 之间相互独立,ReactJS 并不知道数据源发生了什么操作,只能根据新旧两个虚拟 DOM 来猜测需要执行的操作。自动的猜测算法既不准又慢,必须要前端开发者手动提供 key
属性、shouldComponentUpdate
方法、componentDidUpdate
方法或者 componentWillUpdate
等方法才能帮助 ReactJS 框架猜对。
2
AngularJS的脏检查
3
@dom
注解声明数据绑定表达式。@dom
会自动把 =
之后的代码包装成 Binding
类型。比如:@dom val i: Binding[Int] = 1
@dom def f: Binding[Int] = 100
@dom val s: Binding[String] = "content"
@dom
既可用于 val
也可以用于 def
,可以表达包括 Int
、 String
在内的任何数据类型。除此之外,@dom
方法还可以直接编写 XHTML,比如:@dom val comment: Binding[Comment] = <!-- This is a HTML Comment -->
@dom val br: Binding[HTMLBRElement] = <br/>
@dom val seq: Binding[BindingSeq[HTMLBRElement]] = <br/><br/>
@dom
方法都可以依赖其他数据绑定表达式:val i: Var[Int] = Var(0)
@dom val j: Binding[Int] = 2
@dom val k: Binding[Int] = i.bind * j.bind
@dom val div: Binding[HTMLDivElement] = <div>{ k.bind.toString }</div>
render
函数那样描述运算过程。所以当数据发生改变时,只有受影响的部分代码才会重新计算,而不需要重新计算整个 @dom
方法。val count = Var(0)
@dom def status: Binding[String] = {
val startTime = new Date
"本页面初始化的时间是" + startTime.toString + "。按钮被按过" + count.bind.toString + "次。按钮最后一次按下的时间是" + (new Date).toString
}
@dom def render = {
<div>
{ status.bind }
<button onclick={ event: Event => count := count.get + 1 }>更新状态</button>
</div>
}
status
并不是一个普通的函数,而是描述变量之间关系的特殊表达式,每次渲染时只执行其中一部分代码。比如,当 count
改变时,只有位于 count.bind
以后的代码才会重新计算。由于 val startTime = new Date
位于 count.bind
之前,并不会重新计算,所以会一直保持为打开网页首次执行时的初始值。key
、 shouldComponentUpdate
、 $apply
、 $digest
等复杂概念。这些概念在 Binding.scala 中根本不存在。因为 Binding.scala 的 @dom
方法描述的是变量之间的关系。所以,Binding.scala 框架知道精确数据绑定关系,可以自动检测出需要更新的最小部分。4
结论
本文比较了虚拟 DOM 、脏检查和精确数据绑定三种渲染机制。
(点击可查看清晰大图)
三种机制中,Binding.scala 的精确数据绑定机制概念更少,功能更强,性能更高。我将在下一篇文章中介绍 Binding.scala 如何在渲染 HTML 时静态检查语法错误和语义错误,从而避免 bug 。
相关链接: