2016-07-14 49 views
13

作爲摘要循環,如果有100個作用域變量,並且如果我更改了一個變量,那麼它將運行所有變量的監視,對變量進行髒檢查。如何在angularjs中手動停止摘要循環

假設我有100個相互獨立的範圍模型變量。如果我在一個變量中進行更改,那麼我不想檢查所有其他99個變量。有沒有辦法做到這一點?如果是,如何?

+0

因此,沒有這種方式,但明顯地,你可以使用bindonce指令來減少像{{:myVar}}這樣的頁面的監視器,它只會在它不會更新值爲 –

+1

我不能使用一次性綁定。這將從變量中刪除手錶,我需要兩種方式綁定,因爲我正在使用ng-model變量作爲輸入框 –

+0

也許嘗試使用'$ watchCollection' – malix

回答

20

令人驚訝的是,這通常不是問題,即使有成千上萬的綁定,瀏覽器也沒有問題,除非表達式很複雜。 how many watchers are ok to have的共同答案是2000

解決方案:

這是相當距離AngularJS 1.3開始容易,因爲one-time綁定核心了。

  1. 一次綁定變量。

我們可以使用一次綁定(::)指令來阻止觀察者觀察不需要的變量。這裏,變量只會在&之後纔會被觀察一次,之後它不會更新該變量。

  1. 手動停止摘要循環。

HTML:

<ul ng-controller="myCtrl"> 
    <li ng-repeat="item in Lists">{{lots of bindings}}</li> 
</ul> 

控制器代碼:

app.controller('myCtrl', function ($scope, $element) { 
    $element.on('scroll', function() { 
    $scope.Lists = getVisibleElements(); 
    $scope.$digest(); 
    }); 
}); 

$digest,你只改變Lists對象感興趣,不改變個人項目。然而,Angular仍會詢問每個觀察者的變化。

指令爲stoppause摘要:

app.directive('stopDigest', function() { 
    return { 
    link: function (scope) { 
     var watchers; 

     scope.$on('stop', function() { 
     watchers = scope.$$watchers; 
     scope.$$watchers = []; 
     }); 

     scope.$on('resume', function() { 
     if (watchers) 
      scope.$$watchers = watchers; 
     }); 
    } 
    }; 
}); 

現在,控制器代碼應改爲:

<ul ng-controller="listCtrl"> 
    <li stop-digest ng-repeat="item in visibleList">{{lots of bindings}}</li> 
</ul> 

app.controller('myCtrl', function ($scope, $element) { 
    $element.on('scroll', function() { 
    $scope.visibleList = getVisibleElements(); 

    $scope.$broadcast('stop'); 
    $scope.$digest(); 
    $scope.$broadcast('resume'); 
    }); 
}); 

參考文檔:https://coderwall.com/p/d_aisq/speeding-up-angularjs-s-digest-loop

謝謝。

1

這是一個非常特殊的用例,在摘要循環中進行獨佔/條件檢查,並且我認爲沒有分叉/篡改有角的核心是不可能的。

我會考慮重構你/ $watching。也許使用ngModelController$viewChangeListeners$watch更合適?

5

這是一個很好的問題,並強調了Angular 1.x中最大的缺陷之一。幾乎無法控制摘要循環的管理方式。它意味着是一個黑盒子,對於更大的應用程序,這可能會導致嚴重的性能問題。沒有角度的方式做你的建議,但有一些東西可以幫助你實現相同的目標(即 - 只有一件事情發生變化時更好的摘要循環表現)。我想推薦使用bind-notifier plugin。我與這個項目沒有任何關係,但是我將它用於我自己的項目,並取得了巨大的成功。

背後的想法是,你可以指定某些綁定只在特定事件發生時被$消化。

有使用插件的多種方法,但這裏是我發現必須有效的一個:

在模板文件,指定使用綁定的特殊綁定-通知語法:

<div>{{:user-data-change:user.name}}</div> 
<div>{{:job-data-change:job.name}}</div> 

除非通知他們,否則這兩個綁定在大多數摘要循環中不會被骯髒檢查。

在您的控制器,當用戶數據的變化,通知是這樣的綁定:

this.refreshUserData().then(() => { 
    $scope.$broadcast('$$rebind::user-data-change'); 
}); 

(以及類似的job-data-changed

有了這一點,user.name綁定將只在廣播檢查。

有幾件事情要記住:

  1. 這本質上顛覆了角的主要好處(也它是大型應用程序的核心弱點)之一。雙向綁定通常意味着您不需要主動管理對模型的更改,但通過這種方式,您可以這樣做。所以,我只會建議在應用程序中有很多綁定並導致速度減慢的部分使用它。
  2. $emit$broadcast本身可能會影響性能,因此請嘗試僅在$scope樹的少部分(scope s,幾乎沒有子女)調用它們。
  3. 請仔細閱讀文檔,因爲有幾種使用插件的方式。選擇最適合您的應用程序的使用模式。