Angular 1.5.8中带ng-change的Checkbox渲染极慢问题求助
1. 移除模板中的动态函数调用(最核心的优化点)
你现在在ng-repeat的style里直接调用setColour(float.LocationType),Angular的脏检查机制会在每一次digest循环都执行这个函数——哪怕LocationType根本没变化。当列表数据量大的时候,这会产生大量无意义的计算,直接拖慢渲染速度。
解决办法:
- 初始化或更新
floats数组时,预先把颜色值计算好并挂载到每个float对象上:// 比如在获取到floats数据后: $scope.floats.forEach(function(float) { float.bgColour = $scope.setColour(float.LocationType); }); - 模板里直接使用预先计算好的属性:
<div class="row table-row float" ng-repeat="float in floats | orderBy: ['Name', 'Location.Name'] track by float.Id" style="{{float.bgColour}}">
如果后续LocationType可能变化,记得在变化时同步更新bgColour属性,而不是依赖模板实时计算。
2. 优化toggleFloat中的对象查找逻辑
你注释掉的_.find会遍历整个数组查找对象,当floats数组很大时,每次点击复选框都要做一次O(n)的遍历,这也是明显的性能瓶颈。
优化方案:
- 预先建立ID到float对象的映射表,把查找复杂度降到O(1):
// 在初始化floats时创建映射表 $scope.floatMap = {}; $scope.floats.forEach(function(float) { $scope.floatMap[float.Id] = float; }); // 更新toggleFloat函数 $scope.toggleFloat = function(Id) { var float = $scope.floatMap[Id]; // 直接通过ID获取,无需遍历 // 后续逻辑... };
如果floats数组后续会更新(比如新增、删除元素),记得同步更新floatMap。
3. 对静态属性使用一次性绑定
ng-repeat中的Name、Location.Name这类不会变化的静态属性,可以使用AngularJS的一次性绑定语法(::),减少脏检查时需要比对的属性数量:
<div class="row table-row float" ng-repeat="float in floats | orderBy: ['::Name', '::Location.Name'] track by float.Id" style="{{float.bgColour}}"> <!-- 其他静态内容也用一次性绑定 --> <span>{{::float.Name}}</span> <span>{{::float.Location.Name}}</span> <input type="checkbox" class="checkbox" ng-change="toggleFloat(float.Id)" ng-model="float.Selected"/> </div>
注意:float.Selected是会变化的,所以不能用一次性绑定。
4. 减少不必要的watchers
检查你的控制器或指令中,是否存在对floats数组的深度监听(比如$watch('floats', fn, true))。深度监听会在数组中任何元素变化时触发,非常消耗性能。如果不需要深度监听,改成浅监听或者直接移除不必要的watch。
另外,避免在ng-repeat内部使用过多的动态绑定(比如多个ng-bind、ng-class等),每一个绑定都会创建一个watcher,数量过多会导致digest循环变慢。
5. 考虑使用ng-class替代inline style
如果setColour返回的是CSS类名而不是具体的style值,建议用ng-class代替动态style,并且同样预先把类名挂载到float对象上,这样比inline style更高效,也更易维护:
<div class="row table-row float" ng-repeat="float in floats | orderBy: ['::Name', '::Location.Name'] track by float.Id" ng-class="float.bgClass">
内容的提问来源于stack exchange,提问作者notsoobvious

