2016-07-14 46 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. 请仔细阅读文档,因为有几种使用插件的方式。选择最适合您的应用程序的使用模式。