看过一次对 Misko Hevery 的专访,有说到限制2000个对象绑定,可以让页面刷新时间减少到5ms以下。而所谓的刷新时间是指 dirty-checking,因为一次 dirty-checking 时间将会影响 DOM 更新时间。dirty-checking 核心就是对所有 $watch 进行检查。而 bindonce 是为了减少这种不必要的 $watch

什么是 Watch

$watch就是监视数据的变化。这里的数据可能是指令或$scope

比如,以下创建两个$watch,一个文本框、一个名字输出:

<p>用户名:<input type="text" ng-model="name" /></p>
<p>我的用户名:{{name}}</p>

以上,当我在文本框输入字母 a 时,会立即启动一个检查(前期也会有很多工作,比如绑定keydown事件,用于触发事件,这里不再说太多,建议看源代码),会检查到 name 发生变化;这个过程叫dirty-checking,而对所有的 $watch 都检查一遍后,才会将主动权交给浏览器做DOM上的变化(即输出部分)。

试想当我们通过一个 ng-repeat 循环N条记录,而每一行有10个绑定对象,那意味者会有 N*10 个 $watch 等着我们。往往在一个复杂的页面,这种行绑定对象会多得多。

取消 $watch

对于像 ng-repeat,都是由官方提供的,限制是无法限制,所以我们只能在绑定的时候使用传统的方式。而 bindonce 就是这样子的,比如:bo-text 相当于 binder.element.text(value);

注意:bo-text 是以一个指令出现,那么我们需要注意一个问题了,指令是在DOM被加载完全后开始执行,这里的执行顺序非常重要。当你的数据源已经加载完成,此时 bo-text 指令出现,他才能获取到数据,否则永远都是空的。因此这里得出第一个优化规则:

bindonce只能在数据存在时有效

所以对于像表单数据,正常我们都是从 $http.get 来获取,而DOM早就加载完成,所以这个时候再去使用 bindonce 已经没有意义了。

而像SPA很多时候我们会有一些共享的数据,比如版本号、APP名称、用户信息等等,这些信息如果你能够保证在 DOM 加载前就已经存在,那么就可以大胆去使用 bindonce

bindonce 更适合数据列表

$watch 最大的泛滥是数据列表,如我前所说它是N*M在增长。而我们又是通过 ng-repeat 来循环数据,ng-repeat 本身就是一个指令,所以本身会有一个 $watch 来监视数据变化,换句话说我们可以保证 规则一 原则,所以我们大可大胆在 ng-repeat 下去掉我们不需要监视的数据。

所以这里得出第二个优化规则:

ng-repeat下使用bindonce是安全的

在优化之前,我有几点建议:

  1. 绝对不要过早优化,因为NG已经够快的了。
  2. SPA应用加载顺序非常重要。
  3. bindonce适用于数据列表。
  4. 性能的限制因素是人,NG真的非常快。