Javascript 如何处理嵌套ng重复导致的浏览器冻结
我创建了一个嵌套的树,它可能有1-5000个项目,我可以让它工作,但它会在显示树之前冻结我的浏览器\加载微调器几秒钟 如何使其平滑,使浏览器永远不会冻结? 我如何知道angularjs何时完成了整个列表的创建、渲染或计算(不确定是否正确),这样我就可以删除加载微调器,正如您所看到的scope.$last不起作用,因为我们有嵌套的ng repeat,scope也是如此。$parent.$last 这是我用演示数据创建的plunker- 示例数据集- 在本例中情况并不太糟,但在我自己的设置中,我的浏览器在所有其他组件的情况下冻结了大约4000个项目超过10秒 我已经考虑过的Javascript 如何处理嵌套ng重复导致的浏览器冻结,javascript,angularjs,tree,Javascript,Angularjs,Tree,我创建了一个嵌套的树,它可能有1-5000个项目,我可以让它工作,但它会在显示树之前冻结我的浏览器\加载微调器几秒钟 如何使其平滑,使浏览器永远不会冻结? 我如何知道angularjs何时完成了整个列表的创建、渲染或计算(不确定是否正确),这样我就可以删除加载微调器,正如您所看到的scope.$last不起作用,因为我们有嵌套的ng repeat,scope也是如此。$parent.$last 这是我用演示数据创建的plunker- 示例数据集- 在本例中情况并不太糟,但在我自己的设置中,我的
- 使用了bindonce.js库,但没有太大成功
- 使用“:“单次绑定又没有多大成功
- 当用户扩展类别时,只加载第一级然后渲染下一级,但我的树可能非常随机,可能我只有一个根节点和100个子节点
- 分页不适合这种情况
<script type="text/ng-template" id="tree_item">
<div ng-init="category.expanded=true">
<div ng-class="{'selected': category.ID==selectedCategoryID}">
<div class="icon icon16" ng-if="category.Children.length>0" ng-click="$parent.category.expanded=!$parent.category.expanded" ng-class="$parent.category.expanded?'col':'exp'"></div>
<div class="icon icon-category" ng-class="'icon-category-'+category.TypeType" ng-style="{'border-color':category.Colour}" ng-attr-title="{{category.Status?Res['wpOPT_Status'+category.Status]:''}}"></div>
<a ng-href="#id={{category.ID}}" ng-class="{'pending-text': category.PendingChange}">{{category.Name}}</a>
</div>
<ul class="emlist" ng-show="category.expanded">
<li ng-repeat="category in category.Children | orderBy:'Name'" ng-include="'tree_item'" ng-class="{'selected': category.ID==selectedCategoryID}" e2-tree-item is-selected="category.ID==selectedCategoryID">
</li>
</ul>
</div>
</script>
<div id="CategoryListContainer" class="dragmenu-container initial-el-height">
<div class="spinner" data-ng-show="status=='loading'"></div>
<ul id="CategoryList" class="dragmenu-list ng-cloak" ng-show="status=='loaded'">
<li ng-repeat="category in tree | orderBy:'Name'" ng-include="'tree_item'" e2-tree-item is-selected="category.ID==selectedCategoryID"></li>
</ul>
</div>
我的处理方式是: 在控制器中:
// Consider results to be my main array, which contains 5000 items
var results = [{ ... }, { ... }, ..., ..., { ... }];
$scope.bindResults = results.slice(0, 5);
// Here you can start loading
$scope.status = "loading";
// Inject $interval in controller
var interval = $interval(function() {
$scope.bindResults = results.slice(0, $scope.bindResults.length + 5);
if($scope.bindResults.length >= results.length) {
$interval.cancel(interval);
// Here you can end loading
$scope.status = "loading";
}
}, 10);
在HTML中:
<span ng-repeat="x in bindResults"></span>
这不会挂断浏览器,并将每10毫秒填充一次数据,您可以根据需要增加该数字。更新: 演示: 通过如下更改app.js的L10901,您可以顺利加载数据。但是您应该注意到,如果您仍然希望按名称排序,并且希望它稳定,那么您应该只对源数据进行排序,而不应该使用“orderby”按角度排序。(是否需要一些代码来对源数据进行排序?) 顺便说一句,我的电脑上有“1931.881ms”。根据我的经验:
- 将过滤器逻辑移动到JS(不要在HTML中排序,而是在之前排序)
- 使用ng repeat时,请尝试跟踪
- ng include with ng repeat性能不好-请阅读此或此
此外,这是一篇关于angularjs性能与ng repeat的老文章,但很好。建议:您可以使用ng repeat的单向绑定或ng repeat的延迟加载,这可能会对您有所帮助。使用
track by
可以极大地提高性能您应该使用虚拟/无限滚动-既可以使用现有的滚动,也可以开发自己的滚动。没有什么能真正起到作用。我建议使用webworker
让angular在不阻塞主UI线程的情况下完成这项工作。然而,由于angular的这个版本与DOM如此耦合,所以它不是微不足道的。对于Angular2+或React来说,这变得微不足道。无论如何,它使用Web Worker
按名称排序(因此Angular不必这样做),但在重新分配到$scope
时,它不会停止主UI线程的阻塞。如果有人能进一步采用webworker
方法,我很乐意看到它。你的功能不正确。您的$scope.bindResults将始终相同,并且您的间隔将在第一次迭代中取消。这一原则似乎是合理的,但实施是错误的。检查你的切片,如果我想实现类似的东西,但我有嵌套的ng重复和嵌套的数据集,所以这将是非常困难的apply@Ladmerc-是的,你是对的,错过了+5
,更新了答案,如果condition@Mathematics-主数据集大还是嵌套数据集也大,我的主数据集很大,所以worked@Aks1357谢谢你的回答,你有机会看看普朗克吗?我补充道,它有一个例子
<span ng-repeat="x in bindResults"></span>
function getDataGradually(data, childKey, gap, count, updateCb, finishCb) {
const lastPositon = [];
const linearData = [];
const ret = [];
function getLinearData(arr, position) {
arr.forEach(function (obj, index) {
const pos = position.concat([index]);
if (obj[childKey] && obj[childKey].length) {
var children = obj[childKey];
obj[childKey] = [];
linearData.push({
obj,
pos
});
getLinearData(children, pos);
} else {
linearData.push({
obj,
pos
});
}
});
}
getLinearData(data, []);
function insertData({
obj,
pos
}) {
let target = ret;
pos.forEach(function (i, index) {
if (index === pos.length - 1) {
target[i] = obj;
} else {
target = target[i][childKey];
}
});
}
let handled = 0;
function doInsert() {
let start = handled;
let end;
if (handled + count > linearData.length) {
end = linearData.length;
} else {
end = handled + count;
}
for (let i = start; i < end; i++) {
insertData(linearData[i]);
}
handled += count;
if (handled < linearData.length) {
setTimeout(function () {
doInsert();
updateCb && updateCb();
}, gap);
} else {
finishCb && finishCb();
}
}
doInsert();
return ret;
}
$scope.tree = getDataGradually(result.GetCategoryTreeResult, "Children", 0, 30, function () {
$scope.$digest();
}, function () {
//finished
});
//$scope.tree = result.GetCategoryTreeResult;
$scope.status = "loaded";
}, 3000);
$scope.tree = result.GetCategoryTreeResult;
console.time("A")
$timeout(function(){
console.timeEnd("A");
});
$scope.status = "loaded";
}, 3000);