提高性能 ng-repeat 列出 750 个元素
Improve performance ng-repeat list 750 elements
想知道在我的场景中提高性能的最佳方法 750 个元素的列表实时过滤并且没有分页或限制列表的要求,750 个元素应该在屏幕上并且需要被过滤为尽可能快地实时输入文本,显然使用
的性能
ng-repeat="x in collection | filter: x"
这里不太好,有什么想法吗?
编辑:当前情景
<section ng-repeat="(key, value) in content">
<md-subheader class="md-primary">{{ key == '1' ? '#' : key }}</md-subheader>
<md-list layout-padding>
<md-list-item class="md-3-line" ng-repeat="person in value" layout="row">
<div flex="15" flex-md="10" layout="column" layout-align="center center">
<span>{{ ::person.id_lista_nominal }}</span>
</div>
<div class="md-list-item-text" flex>
<h3>{{ ::person.nombre_completo }}</h3>
<h4>{{ ::person.ine }}</h4>
</div>
<div flex="15" flex-md="10" layout="column" layout-align="center center">
<md-button aria-label="Votó" class="md-primary md-raised text-white" ng-click="confirm_voting(person, $event)"><md-icon md-font-icon="mdi-navigation-check icon-md"></md-icon> </md-button>
</div>
</md-list-item>
</md-list>
</section>
现在所有的过滤都在控制器中以获得更好的性能,在这个函数中
var update_list_content = function () {
//filter implementation in controller
var tmp = angular.copy(original);
tmp = $filter('filterBy')(tmp, ['nombre_completo', 'nombre_inverso'], $scope.param.search);
tmp = $filter('orderBy')(tmp, 'nombre_completo');
tmp = $filter('limitTo')(tmp, $scope.config.limit);
tmp = $filter('groupBy')(tmp, 'grupo');
$scope.content = tmp;
};
由于指出正确,我在这里的目标还不是很清楚,所以这里是:
我正在使用 cordova 开发一个移动应用程序,所有这些在 PC 上运行良好且流畅,但在移动设备上感觉有点滞后
在这里我有一个像联系人列表一样的列表,第一个 ng-repeat 重新排序列表并将列表分成组(sub-header 是组名)
嵌套ng-repeat用于显示每个组内的人员列表
此屏幕的过程非常简单,因此不能接受滞后的界面
用户只能通过滚动列表或按人名过滤在列表中进行搜索,每个人的按钮都会询问用户是否同意 "mark" 处理联系人,如果用户同意处理将执行一个简单的 websql 命令,通过其 id 将 mark = 1 设置为所选人员,并将该人员从列表中删除。
但是过滤列表中的屏幕上的 750 个人感觉有问题,每次用户标记一个人时,更新列表并显示标记的删除需要 3 或 4 秒
想要的体验是流畅的滚动、快速的搜索和标记后的立即删除,我知道如果我限制屏幕上的人数(比如 50)我在这个过程中获得了很多性能但遗憾的是对我来说,这不是一个选择,除非也许管理一种模拟它们可以上下滚动但限制显示数据量的方法:S
限制最初显示的元素数量,然后在用户滚动时显示更多元素。就像 tweeter 无限滚动(当用户到达页面底部时,它会加载更多推文)
- 以某种方式简化您的过滤器,以便您的控制器或服务生成应该列出的项目,而不是在视图中这样做。
(key, value) in filteredContent()
另一个想法是使用 https://github.com/Pasvaz/bindonce 并在可能的情况下更新事件的数据。
- 只要将您的观看次数保持在 1,200 以下(当我遇到缓慢时),您就会没事的。 http://www.bennadel.com/blog/2698-counting-the-number-of-watchers-in-angularjs.htm
否则我会 google 减少监视计数并为 AngularJS 编写有效的过滤器。
您没有说明您的要求...AngularJS对于大量数据来说可能非常繁重,但 750 个简单项目应该不是问题。您有多种选择:
将您的过滤器输入更改为具有延迟,这样它就不会更改每个按键上的 model
。首先不要在过滤器上监听 param.search
,而是监听其他变量 searchText
.
例如:
$scope.$watch('param.search', function (newValue) {
if (searchTextTimeout) {
$timeout.cancel(searchTextTimeout);
}
searchTextTimeout= $timeout(function() {
$scope.searchText= newValue;
}, 300); // between 200-300 ms should be a good user experience
});
你也可以应用React,延迟过滤。如果你的表现仍然很差,可能问题出在你的风格上,一个单一的风格可能会导致大量的重绘,例如,如果你在过滤时为 position
变化设置动画,那么动画就会非常缓慢。
希望这对你有用。
更新
我还注意到您正在使用此指令 md-subheader,它似乎只添加了一个 #1 或关键您需要显示的内容?如果是你可以使用 $index 的计数
我想我找到了解决我自己问题的方法谷歌搜索各种类型的解决方法我找到了这个
一个很棒的指令,直接在 angular 的 ng-repeat 循环上管理虚拟滚动的概念,这样视图在滚动时只呈现几个项目,它会加载其余项目,但与延迟加载用户不同向下滚动时看不到滚动条增加,因为它已经计算了 space 并且它删除了您在视口外滚动的元素,因此,您将始终拥有 'illusion' 的全套项目只呈现几个
你不必限制元素本身的数量,但如果你检测到它,你可以在滚动事件上加载它们。
举个例子,我承认你使用一个通用的 mysql 数据库存储你的所有数据,我使用两个变量来做到这一点并获得我所有的用户评论,看起来像那样(阅读评论):
//Function to get all comments progressively
$scope.getAllCommentsByUserId = function(){
//action name, here actionVar's value will be my php case, if
//$_POST['action'] equal this value then i will send my sql request
var actionVar = "getAllCommentsByUserId";
//Define callback function
var callback = function(resp){
if(resp.success == 1){
// $scope.userComments will be my array were the sql results
// from resp will be stored, also it's the main varaible of
// my ng-repeat loop, i push them because i don't want
// to erase the comments i already requested, so the new ones
// will be at the end of the array
angular.forEach(resp.comments, function(comment, key) {
$scope.userComments.push(comment);
});
// In case i got an error istead of a good result
}else{
$scope.$emit('showAlert', ["Une erreur est survenue","error"]);
}
};
// In case you want to know, userId is not needed, i use it just to
// request all the comments on the current user's page. that's just logic.
var params = {
'action' : actionVar,
'idUser' : $scope.bigouder.idUser,
'begin' : $scope.beginComments,
'length' : $scope.lengthComments
};
//HTTP REQUEST
$http.post(url, params)
.success(callback)
.error(function(){
$scope.$emit('showAlert', ["ERROR","error"]);
});
};
// I update the begining element index by adding the length to it
// YOU HAVE TO SET "beginComments" AND "lengthComments" AT THE BEGINING OF
// YOUR JS FILE, to give them a default value, otherwise that will never work.
$scope.changeMaxComments = function(){
$scope.beginComments += $scope.lengthComments;
$scope.lengthComments = 20;
$scope.getAllCommentsByUserId();
};
基本上我在这里做的是设置 2 个值:
- beginComments 和 lengthComments
beginComments 将是我的 sql 请求开始保存找到的结果的元素,lengthComments 将是我将保存的结果数。
sql 请求将是这样的:$query = "select ... from ... where ... order by ... limit". $_POST['begin'] . "," $_POST['length'];
所以我在我的 sql 请求中使用我的两个变量和限制参数,我将把所有结果从 "beginComments" 元素带到 "beginComments + lengthComments" 元素。
你只需要在检测到滚动事件时调用类似的东西,angular 就会完成这项工作并刷新你的 ng-repeat。 :)
想知道在我的场景中提高性能的最佳方法 750 个元素的列表实时过滤并且没有分页或限制列表的要求,750 个元素应该在屏幕上并且需要被过滤为尽可能快地实时输入文本,显然使用
的性能ng-repeat="x in collection | filter: x"
这里不太好,有什么想法吗?
编辑:当前情景
<section ng-repeat="(key, value) in content">
<md-subheader class="md-primary">{{ key == '1' ? '#' : key }}</md-subheader>
<md-list layout-padding>
<md-list-item class="md-3-line" ng-repeat="person in value" layout="row">
<div flex="15" flex-md="10" layout="column" layout-align="center center">
<span>{{ ::person.id_lista_nominal }}</span>
</div>
<div class="md-list-item-text" flex>
<h3>{{ ::person.nombre_completo }}</h3>
<h4>{{ ::person.ine }}</h4>
</div>
<div flex="15" flex-md="10" layout="column" layout-align="center center">
<md-button aria-label="Votó" class="md-primary md-raised text-white" ng-click="confirm_voting(person, $event)"><md-icon md-font-icon="mdi-navigation-check icon-md"></md-icon> </md-button>
</div>
</md-list-item>
</md-list>
</section>
现在所有的过滤都在控制器中以获得更好的性能,在这个函数中
var update_list_content = function () {
//filter implementation in controller
var tmp = angular.copy(original);
tmp = $filter('filterBy')(tmp, ['nombre_completo', 'nombre_inverso'], $scope.param.search);
tmp = $filter('orderBy')(tmp, 'nombre_completo');
tmp = $filter('limitTo')(tmp, $scope.config.limit);
tmp = $filter('groupBy')(tmp, 'grupo');
$scope.content = tmp;
};
由于指出正确,我在这里的目标还不是很清楚,所以这里是:
我正在使用 cordova 开发一个移动应用程序,所有这些在 PC 上运行良好且流畅,但在移动设备上感觉有点滞后
在这里我有一个像联系人列表一样的列表,第一个 ng-repeat 重新排序列表并将列表分成组(sub-header 是组名)
嵌套ng-repeat用于显示每个组内的人员列表
此屏幕的过程非常简单,因此不能接受滞后的界面
用户只能通过滚动列表或按人名过滤在列表中进行搜索,每个人的按钮都会询问用户是否同意 "mark" 处理联系人,如果用户同意处理将执行一个简单的 websql 命令,通过其 id 将 mark = 1 设置为所选人员,并将该人员从列表中删除。
但是过滤列表中的屏幕上的 750 个人感觉有问题,每次用户标记一个人时,更新列表并显示标记的删除需要 3 或 4 秒
想要的体验是流畅的滚动、快速的搜索和标记后的立即删除,我知道如果我限制屏幕上的人数(比如 50)我在这个过程中获得了很多性能但遗憾的是对我来说,这不是一个选择,除非也许管理一种模拟它们可以上下滚动但限制显示数据量的方法:S
限制最初显示的元素数量,然后在用户滚动时显示更多元素。就像 tweeter 无限滚动(当用户到达页面底部时,它会加载更多推文)
- 以某种方式简化您的过滤器,以便您的控制器或服务生成应该列出的项目,而不是在视图中这样做。
(key, value) in filteredContent()
另一个想法是使用 https://github.com/Pasvaz/bindonce 并在可能的情况下更新事件的数据。- 只要将您的观看次数保持在 1,200 以下(当我遇到缓慢时),您就会没事的。 http://www.bennadel.com/blog/2698-counting-the-number-of-watchers-in-angularjs.htm
否则我会 google 减少监视计数并为 AngularJS 编写有效的过滤器。
您没有说明您的要求...AngularJS对于大量数据来说可能非常繁重,但 750 个简单项目应该不是问题。您有多种选择:
将您的过滤器输入更改为具有延迟,这样它就不会更改每个按键上的
model
。首先不要在过滤器上监听param.search
,而是监听其他变量searchText
.
例如:
$scope.$watch('param.search', function (newValue) {
if (searchTextTimeout) {
$timeout.cancel(searchTextTimeout);
}
searchTextTimeout= $timeout(function() {
$scope.searchText= newValue;
}, 300); // between 200-300 ms should be a good user experience
});
你也可以应用React,延迟过滤。如果你的表现仍然很差,可能问题出在你的风格上,一个单一的风格可能会导致大量的重绘,例如,如果你在过滤时为 position
变化设置动画,那么动画就会非常缓慢。
希望这对你有用。
更新
我还注意到您正在使用此指令 md-subheader,它似乎只添加了一个 #1 或关键您需要显示的内容?如果是你可以使用 $index 的计数
我想我找到了解决我自己问题的方法谷歌搜索各种类型的解决方法我找到了这个
一个很棒的指令,直接在 angular 的 ng-repeat 循环上管理虚拟滚动的概念,这样视图在滚动时只呈现几个项目,它会加载其余项目,但与延迟加载用户不同向下滚动时看不到滚动条增加,因为它已经计算了 space 并且它删除了您在视口外滚动的元素,因此,您将始终拥有 'illusion' 的全套项目只呈现几个
你不必限制元素本身的数量,但如果你检测到它,你可以在滚动事件上加载它们。
举个例子,我承认你使用一个通用的 mysql 数据库存储你的所有数据,我使用两个变量来做到这一点并获得我所有的用户评论,看起来像那样(阅读评论):
//Function to get all comments progressively
$scope.getAllCommentsByUserId = function(){
//action name, here actionVar's value will be my php case, if
//$_POST['action'] equal this value then i will send my sql request
var actionVar = "getAllCommentsByUserId";
//Define callback function
var callback = function(resp){
if(resp.success == 1){
// $scope.userComments will be my array were the sql results
// from resp will be stored, also it's the main varaible of
// my ng-repeat loop, i push them because i don't want
// to erase the comments i already requested, so the new ones
// will be at the end of the array
angular.forEach(resp.comments, function(comment, key) {
$scope.userComments.push(comment);
});
// In case i got an error istead of a good result
}else{
$scope.$emit('showAlert', ["Une erreur est survenue","error"]);
}
};
// In case you want to know, userId is not needed, i use it just to
// request all the comments on the current user's page. that's just logic.
var params = {
'action' : actionVar,
'idUser' : $scope.bigouder.idUser,
'begin' : $scope.beginComments,
'length' : $scope.lengthComments
};
//HTTP REQUEST
$http.post(url, params)
.success(callback)
.error(function(){
$scope.$emit('showAlert', ["ERROR","error"]);
});
};
// I update the begining element index by adding the length to it
// YOU HAVE TO SET "beginComments" AND "lengthComments" AT THE BEGINING OF
// YOUR JS FILE, to give them a default value, otherwise that will never work.
$scope.changeMaxComments = function(){
$scope.beginComments += $scope.lengthComments;
$scope.lengthComments = 20;
$scope.getAllCommentsByUserId();
};
基本上我在这里做的是设置 2 个值:
- beginComments 和 lengthComments
beginComments 将是我的 sql 请求开始保存找到的结果的元素,lengthComments 将是我将保存的结果数。
sql 请求将是这样的:$query = "select ... from ... where ... order by ... limit". $_POST['begin'] . "," $_POST['length'];
所以我在我的 sql 请求中使用我的两个变量和限制参数,我将把所有结果从 "beginComments" 元素带到 "beginComments + lengthComments" 元素。
你只需要在检测到滚动事件时调用类似的东西,angular 就会完成这项工作并刷新你的 ng-repeat。 :)