Angular 1.3 one-time binding介紹

Angular 1.3 版本終於放出,在更新了許多新特性的同時也修復了許多bug而且帶來性能提高。爲了幫助本身也幫助別人更早理解這些新特性,接下來將會有一個系列文章去介紹這些主要的新特性和改進。本片文章是這個系列的第一篇,將介紹這其中最重要的一個新特性:one-time bindng。html

唉,先別急!我記得Angular的數據綁定是自動保持UI同步更新的啊?沒錯,這個特色很是重要,但不必定全部地方都須要。這種數據綁定的方式須要框架時刻監視着全部綁定過的數據,這種方式真的很消耗性能。one-time binding 正是爲解決此問題而生的。在介紹 one-time binding 以前,先理解一下數據綁定和watcher的的概念。angularjs

理解數據綁定和watchers

爲了實現數據綁定,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

太多watcher的問題

如今咱們已經對 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 binding 來拯救大家了!

終於到了主角登場的時刻了。那麼什麼是 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不會再發生改變!

原文連接

相關文章
相關標籤/搜索