Angular 1.3 版本终于放出,在更新了许多新特性的同时也修复了许多bug而且带来性能提高。为了帮助本身也帮助别人更早理解这些新特性,接下来将会有一个系列文章去介绍这些主要的新特性和改进。本片文章是这个系列的第一篇,将介绍这其中最重要的一个新特性:one-time bindng。html
唉,先别急!我记得Angular的数据绑定是自动保持UI同步更新的啊?没错,这个特色很是重要,但不必定全部地方都须要。这种数据绑定的方式须要框架时刻监视着全部绑定过的数据,这种方式真的很消耗性能。one-time binding 正是为解决此问题而生的。在介绍 one-time binding 以前,先理解一下数据绑定和watcher的的概念。angularjs
为了实现数据绑定,Angular 使用了 $watch API去观察 scope 上的数据的改动。其中 scope 具体是什么如何造成的取决于你的代码。若是你没有手动建立一个 child scope ,例如经过 ngController 指令去建立,那么你多是在和 $rootScope 打交道,这个 $rootScope 是指当前应用的通常经过 ngApp 指令建立的根 scope。express
和 scope 打交道并观察其中的变化通常老是要用到所谓的 watcher 。Watchers 经过 DOM 中的 directives 注册。比方说经过直接 interpolation 指令去同步 scope 模型的值:api
<p>Hello {{name}}!</p>
这个 interpolation 指令注册了一个用于 $rootScope 上 name 属性的 watcher,从而能够更新绑定了这个属性值的DOM。app
咱们能够在 socpe 上经过标识符直接定义一个属性并同时给它赋值,这样它就能够直接在DOM中显示:框架
angular.module('maApp', []) .run(function($rootScope) { $rootScope.name = 'Pascal'; });
咱们刚刚经过 interpolation 指令在 view 上绑定了一了一个 model 值,若是改变它的值,view 也会同时自动更新。能够经过添加一个按钮实现更新 name 属性值的操做:ide
<button ng-click="name = 'Christoph'">Click me!</button>
点击这个按钮会把 Christoph 赋给 name 属性,这触发了一个 $digest 能够保持 DOM 相应更新的轮询。在这个例子中数据的更新只是单向的(上->下)。若是是在用到 ngModel 的 input 元素的例子中,用户能够输入内容改变这个属性的值,同时改变也实时的返回到实际的 model 上。性能
这些是由于一个 $digest 轮询被触发才发生的,Angular 负责处理全部当前 scope 和它的 child scope 上注册过的 watchers,并检查 model 是否通过改动,而后直到 model 稳定调用而且没有更多的 listeners 被点燃,对应的 listeners 被调用。
如下是以上描述的代码效果展现:
plnkrui
如今咱们已经对 Angular 中的数据绑定机制有了一个大体的了解,那么可能想到为何会须要 one-time binding 这样的特性呢?code
鉴于使用 watcher 来实现数据绑定的本质,咱们可能会遇到有太多 watcher 时较差性能的问题。正如咱们所了解的那样,watch expressions 和他们对应的 callback listeners 都是是注册在 scope 上的,基于此 Angular 能够在 $digest 轮询的时候处理它们也就保持了相应的 view 更行。简单地说,越多 watchers 被注册,Angular 要处理的也就越多。
如今想象一种有许多动态值在 view 中的场景。好比国际化过程是很是常见的一种状况,须要 Angular 的数据绑定去作应用的本地化,尽管语言只在初始设置页才会更改,而在运行时是不会改变的。此情景下每个字符串都被本地化到 view 中,同时也被写入到 scope 里,而且注册一个对应的 watcher 用于下次 $digest 轮询时可能的更新。若是语言的确不太可能在运行时改变,这样的代价实在是过高了。
终于到了主角登场的时刻了。那么什么是 one-time bindings ?文档里是这么说的:
One-time expressions will stop recalculating once they are stable, which happens after the first digest…
第一次 digest 后,One-time 表达式一旦稳定后就不会再更新。
上面提到的场景的确是 Angular 应当处理的问题。Angular 1.3 中引入了一种新语法用于表示 interpolation 指令绑定的 one-time。只须要在表达式前加入 ::
双引号便可。一样是上面的例子,咱们只须要把:
<p>Hello {{name}}!</p>
改成:
<p>Hello {{::name}}!</p>
这一样适用于其余 Angular 中典型的表达式。例如在 ng-repeat 表达式中或者仅须要从内部暴露出一个属性值的指令(不会从外部改变),只须要在外部把它设置为 one-time 表达式:
<custom-directive two-way-attribute="::oneWayExpression"></custom-directive>
下面是实际例子中的效果,已经把上面例子中的 name 改为了 ::name表示 one-time binding,其余则代码彻底同样。注意按钮的做用是把 name 更新为 Christoph,不过再试试看:
plnkr
name不会再发生改变!