毫无疑问。通过互联网搜索,您可以轻松找到ng-repeat和复选框如何工作的示例。所有这些示例仅包含几个复选框。但是,您是否尝试创建数百个复选框,然后使用一些切换按钮来选中/取消选中所有复选框?该应用程序变得完全没有响应。在浏览器中它是好的,但在设备上测试应用程序(iPad4,iPad mini等),该应用程序完全没有响应。
我在这里创建了一个Plunker示例:http://plnkr.co/edit/wfa3TIp3BYaPvzX8ehAf?p=preview
尝试使用至少500个条目来测试切换复选框,以便您可以看到延迟。现在的问题是,有什么方法可以提高性能?检查时间轴的记录,这是我得到500个条目的结果(:
19.131 ms Scripting
150.104 ms Rendering
55.543 ms Painting
138.402 ms Other
2.95 s Idle
正如你所看到的,渲染花费了宝贵的时间,我们无法承受失去的那段时间。
HTML:
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width" />
<title>Ionic Framework Example</title>
<link href="//code.ionicframework.com/nightly/css/ionic.css" rel="stylesheet"/>
<link href="index.css" rel="stylesheet"/>
<script src="//code.ionicframework.com/nightly/js/ionic.bundle.js"></script>
<script src="script.js"></script>
</head>
<body>
<ion-view view-title="main module">
<ion-content ng-controller="StartCtrl">
<div class="list">
<div class="item item-divider">
Options
</div>
<a class="item item-icon-left" href="#" ng-click="generateEntries()">
<i class="icon ion-plus-circled"></i>
Add more entries
</a>
<a class="item item-icon-left" href="#" ng-click="clearEntries()">
<i class="icon ion-trash-b"></i>
Clear entries
</a>
<div class="item item-icon-left" href="#">
<i class="icon ion-person-stalker"></i>
Entries in array
<span class="badge badge-assertive">{{entries.length}}</span>
</div>
<li class="item item-checkbox">
<label class="checkbox">
<input type="checkbox" ng-model="checkedAll" ng-click="toggleAll()">
</label>
Toggle all
</li>
<div class="item item-divider">
Entries
</div>
<li class="item item-checkbox" ng-repeat="entry in entries track by $index">
<label class="checkbox">
<input type="checkbox" ng-model="entry.checked" name="entry.id">
</label>
{{entry.id}} - {{entry.name}}
<span class="badge badge-light">{{$index}}</span>
</li>
</div>
</ion-content>
</ion-view>
</body>
</html>
JS:
// Code goes here
var app = angular.module('myApp', []);
app.controller('StartCtrl', function ($scope) {
// bind data from service
// this.someData = Start.someData;
$scope.entries = [];
$scope.generateEntries = function () {
var names = ['Mark', 'John', 'Maria', 'Lea', 'Marco'];
var obj = {};
for (var i = 0; i < 50; i++) {
obj = {'id': Math.floor(Math.random() * 10000), 'name': names[Math.floor(Math.random() * names.length)]};
$scope.entries.push(obj);
}
};
$scope.clearEntries = function () {
$scope.entries = [];
};
$scope.toggleAll = function () {
for (var i = 0; i < $scope.entries.length; i++) {
$scope.entries[i].checked = $scope.checkedAll;
}
};
});
感谢所有参与此次讨论的人。
答案 0 :(得分:1)
使用entry in entries track by entry.id
代替$index
。有500个条目,这改善了我的统计数据:
使用track by $index
65.660 ms Scripting
246.985 ms Rendering
129.748 ms Painting
1.23 s Other
3.31 s Idle
使用track by entry.id
46.534 ms Scripting
30.827 ms Rendering
17.631 ms Painting
226.515 ms Other
3.18 s Idle
答案 1 :(得分:0)
来自@Numyx和@jaycp的回复都非常有帮助。我对代码做了一些改进:
1.我使用track by entry.id
而不是track by $index
来加速渲染,因为@Numyx说,
2.我已经使用ion-infinite-scroll因此我不会同时加载所有结果(例如5000),但只能加载约。 25.滚动到底部加载更多。
3.我使用了2个数据集。所有条目均为1,视图条目为1。滚动时填充视图条目数组。滚动越多,ALL数组中的条目就越多,添加到视图数组中,
4.我在渲染完成时使用$ timeout来显示$ ionicLoading并隐藏$ ionicLoading,
因此,当使用切换按钮时,现在我们不会将所有条目设为已选中,而只是那些处于可见数组中的条目。
以下是更新后的代码:
<强>的start.html 强>
<ion-view view-title="main module">
<ion-content>
<div class="list">
<div class="item item-divider">
Options
</div>
<a class="item item-icon-left" href="#" ng-click="start.generateEntries()">
<i class="icon ion-plus-circled"></i>
Add more entries
</a>
<a class="item item-icon-left" href="#" ng-click="start.clearEntries()">
<i class="icon ion-trash-b"></i>
Clear entries
</a>
<div class="item item-icon-left" href="#">
<i class="icon ion-person-stalker"></i>
Entries in array
<span class="badge badge-assertive">{{start.entries.length}}</span>
</div>
<li class="item item-checkbox">
<label class="checkbox">
<input type="checkbox" ng-model="start.checkedAll" ng-click="start.toggleAll()">
</label>
Toggle all
</li>
<div class="item item-divider">
Entries {{start.entriesView.length}}
</div>
<li class="item item-checkbox" ng-repeat="entry in start.entriesView track by entry.id">
<label class="checkbox">
<input type="checkbox" ng-model="entry.checked" name="entry.id">
</label>
{{entry.id}} - {{entry.name}}
<span class="badge badge-light">{{$index}}</span>
</li>
<ion-infinite-scroll
on-infinite="start.loadMore()"
ng-if="start.canLoadMore()"
immediate-check="false"
distance="1%">
</ion-infinite-scroll>
</div>
</ion-content>
</ion-view>
开始-ctrl.js 强>
'use strict';
angular.module('main')
.controller('StartCtrl', function (Utility, $timeout, $scope) {
// bind data from service
// this.someData = Start.someData;
this.entries = [];
this.entriesView = [];
this.numEntriesToCreate = 5000;
this.numEntriesToAdd = 25;
var self = this;
$scope.$on('$stateChangeSuccess', function () {
console.log('START');
self.loadMore();
});
/**
* generate more entries
*/
this.generateEntries = function () {
var names = ['Gregor', 'Mathias', 'Roland', 'Jonas', 'Marco'];
var obj = {};
for (var i = 0; i < self.numEntriesToCreate; i++) {
obj = {'id': Math.random() + Math.random() * 10000, 'name': names[Math.floor(Math.random() * names.length)]};
self.entries.push(obj);
}
};
this.clearEntries = function () {
self.entries = [];
};
this.toggleAll = function () {
self.startLoading();
console.log(self.checkedAll);
// we wait for spinner to appear (500ms), then start..
$timeout(function () {
for (var i = 0; i < self.entriesView.length; i++) {
self.entriesView[i].checked = self.checkedAll;
}
self.finishedLoading();
}, 500);
};
this.loadMore = function () {
if (self.canLoadMore()) {
// self.startLoading();
$timeout(function () {
self.entriesView = self.entriesView.concat(
self.entries.slice(self.entriesView.length, self.entriesView.length + self.numEntriesToAdd) // exact items from our original entries
);
$scope.$broadcast('scroll.infiniteScrollComplete');
// self.finishedLoading();
}, 500);
}
//
};
this.canLoadMore = function () {
return (self.entriesView < self.entries) ? true : false;
};
this.startLoading = function () {
Utility.startTimer();
Utility.showLoading();
};
this.finishedLoading = function () {
$timeout(function () {
Utility.hideLoading();
console.log('execution took ' + Utility.endTimer() + 'ms.');
});
};
console.log('init. creating ' + self.numEntriesToCreate + ' entries');
self.generateEntries();
});
<强>效用serv.js 强>
'use strict';
angular.module('main')
.service('Utility', function ($ionicLoading) {
this.opt = {
startTime: null
};
this.showLoading = function () {
$ionicLoading.show({template: '<ion-spinner></ion-spinner>'});
};
this.hideLoading = function () {
$ionicLoading.hide();
};
this.startTimer = function () {
this.opt.startTime = new Date().getTime();
};
this.endTimer = function () {
return ((this.opt.startTime) ? new Date().getTime() - this.opt.startTime : null);
};
});
我还发布了完整的example on GitHub。项目是使用generator-m生成的。您只需克隆github并使用gulp watch
命令运行它。