AngularJS复选框渲染第一次非常慢

时间:2017-04-10 17:20:21

标签: javascript angularjs checkbox

我遇到了运行Angular 1.5.9的旧应用程序的问题。控制器包含以下循环,该循环由" Select All"页面上的链接:

                var len = $scope.payments.length, i;
                for (i = 0; i < len; i++) {
                    $scope.payments[i].selected = true;
                }

payment数组中对象中的selected属性绑定到视图中的复选框:

<tr data-ng-repeat="payment in payments | orderBy: 'payDate'">
    <td><input type="checkbox" data-ng-model="payment.selected" data-ng-change="setSelectedTotal()"/>...

表中的数组/行中最多有15000个项目,并且在页面加载后第一次单击“全选”链接时,最多需要40秒才能刷新视图并选中所有复选框。如果我清除复选框,然后再次单击“全选”链接,则复选框将在大约1秒或更短的时间内显示为已选中。所有随后点击“全选”链接的情况都是如此 - 它只是第一次变慢,但每次只需要一秒或更短时间。我怀疑这与模型绑定有关,因为当我用console.time()和console.timeEnd()包围循环时,循环只需要几秒钟甚至第一次尝试。所以问题在于循环完成后发生的事情。我尝试过从ng-model切换到ng-checked只是为了看看它是否会加快速度,但它给了我一个错误,实际上应用程序依赖于绑定到所选属性的复选框。我还尝试在页面加载的第一千个复选框上运行select all(后面是全部清除),但这没有任何区别。任何洞察它为什么第一次如此缓慢和/或如何加快它将非常感激。

1 个答案:

答案 0 :(得分:1)

以下是一些优化示例。

  

注意:我使用document.querySelectorAll在控制器之外选择/取消选择,因为它比依赖$ scope数据快得多。

angular.module('app', []);

angular.module('app')
    .controller('ExampleController', ['$scope', function($scope) {

        $scope.payments = [];
        $scope.selected = false;
        $scope.total = 0;
        $scope.itemsCount = 7500;

        // Populate with 
        populate($scope.itemsCount);

        $scope.updateTotal = function() {
            let total = 0;
            for (let i = 0; i < $scope.payments.length; i++) {
                if ($scope.payments[i].selected === true) {
                    total += $scope.payments[i].amount;
                }
            }
            $scope.total = total;
        }

        $scope.toggleAll = function() {
            // Toggle global selected state
            $scope.selected = !$scope.selected;
            for (let i = 0; i < $scope.payments.length; i++) {
                $scope.payments[i].selected = $scope.selected;
            }
            $scope.updateTotal();
        }

        $scope.toggle = function(index) {
            $scope.payments[index].selected = !$scope.payments[index].selected;
            $scope.updateTotal();
        }

        function populate(count) {
            for (let i = 0; i < count; i++) {
                $scope.payments.push({
                    amount: i,
                    selected: false
                });
            }
        }

    }]);


// Toggle all checkbox

function vanillaToggleAll(event) {
    var el = event.srcElement || event.target;
    var checkboxes = document.querySelectorAll("input[type='checkbox']");
    for (let i = 0; i < checkboxes.length; i++) {
        checkboxes[i].checked = el.checked;
    }
}
<!doctype html>

<html lang="en" ng-app="app">
<head>
  <meta charset="utf-8">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.4/angular.min.js"></script>
  <script src="script.js"></script>
</head>
 
<body ng-controller="ExampleController">

<h1>Items: {{itemsCount}}, Total: {{total}} USD</h1>

<table>
	<thead>
	  <tr>
  		<td>
  			<input type="checkbox" ng-click="toggleAll()" onclick="vanillaToggleAll(event)">
  			<label>Select/Unselect All</label>
  		</td>
	  </tr>
	</thead>
	<tbody>
		<tr ng-repeat="payment in payments | orderBy: 'amount'">
	    	<td>
	    		<input type="checkbox" class="checkbox" ng-bind="payment.selected" ng-click="toggle($index)" />
	    		<label ng-bind="::payment.amount"></label> USD
	    	</td>
	    </tr>
	</tbody>    
</table>    
</body>
</html>

A demo plunker 7500 项目

以下是结果,我使用Chrome分析器来分析加载,编写脚本,渲染所花费的时间......

1000件

enter image description here

10000件

enter image description here

15000件

enter image description here