我正在构建一个复杂的角度应用程序,它具有无限滚动,具有类似马赛的列和图像。我做了一项研究,并编写了自己的指令来为我呈现数据:
angular.module('deepsy.flexgrid', []);
angular.module('deepsy.flexgrid').directive('flexgrid', [
'flexgridFactory',
function initialize(flexgridFactory) {
return flexgridFactory.create();
}
]);
angular.module('deepsy.flexgrid').factory('flexgridFactory', [
'FlexGrid',
'$log',
function initialize(FlexGrid, $log) {
function Creator() {
this.restrict = 'AE';
this.scope = {
'model': '=source',
'opts': '=options'
};
this.$$grid = null;
this.link = this.$$link.bind(this);
}
Creator.prototype.$$link = function $$link(scope, elem, attrs) {
scope.itemTemplate = attrs.template;
scope.mother = scope.$parent;
scope.template = elem.html();
elem.html('');
this.$$grid = new FlexGrid(scope, elem);
};
return {
create: function create() {
return new Creator();
}
};
}
]);
angular.module('deepsy.flexgrid').factory('FlexGrid', [
'$compile',
function($compile) {
function FlexGrid(scope, elem) {
this.scope = scope;
this.elem = elem;
this.state = null;
this.counter = 0;
this.id = Math.floor(Math.random() * 999);
this.$getColumns();
this.$createColumns();
window.onresize = this.$watchSize.bind(this);
this.scope.$watch(function() {
return this.scope.model;
}.bind(this), this.$applyData.bind(this), true);
}
FlexGrid.prototype.$getColumns = function() {
var curr = null,
width = document.body.clientWidth,
min, max;
for (var i in this.scope.opts.columns) {
curr = this.scope.opts.columns[i];
min = curr.min || 0;
max = curr.max || 99999;
if (min < width && width < max) {
this.state = curr;
return curr;
}
}
};
FlexGrid.prototype.$createColumns = function() {
var output = [];
for (var i = 0; i < this.state.columns; i++) {
output.push('<div id="flexgrid_' + this.id + '_' + i + '" class="gridColumns ' + this.state.class + '"></div>');
}
this.elem.html(output.join(''));
};
FlexGrid.prototype.$watchSize = function() {
var curr = this.state || {
columns: 0
};
this.$getColumns();
if (this.state.columns != curr.columns) {
this.$createColumns();
this.$fillData(0);
}
};
FlexGrid.prototype.$applyData = function(newVal, oldVal) {
var bindings = [],
count = 0;
oldVal.forEach(function(obj) {
bindings.push(obj._id);
});
newVal.forEach(function(obj) {
if (bindings.indexOf(obj._id) != -1) {
count++;
}
});
if (count == oldVal.length && oldVal.length > 0) {
this.$fillData(count);
// console.log('add');
} else {
this.$fillData(0);
// console.log('render');
}
};
FlexGrid.prototype.$fillData = function(start) {
var columns = this.state.columns,
len = this.scope.model.length;
if (start === 0) {
this.$clearColumns(columns);
this.counter = 0;
}
for (var i = start; i < len; i++) {
$("#flexgrid_" + this.id + "_" + this.counter).append(this.$compile(this.scope.model[i]));
if (this.counter++ === columns - 1)
this.counter = 0;
}
//$("img", this.elem).load(function(){
// $(this).parent().fadeIn(700);
//});
};
FlexGrid.prototype.$compile = function(data) {
var compiled = this.scope.template.replace(/\{\|[^\|\}]*\|\}/gmi, function(exp, val) {
return data[exp.replace(/\|\}|\{\|/gmi, '')];
});
compiled = compiled.replace('src-image', 'src="' + data.image + '" dinimg');
return compiled;
};
FlexGrid.prototype.$clearColumns = function(columns) {
for (var j = 0; j < columns; j++) {
$("#flexgrid_" + this.id + "_" + j).empty();
}
};
return FlexGrid;
}
]);
它工作得很棒,但有一些性能问题。我首先喜欢“嗯......我可能有太多观察者”,但后来我优化了我的代码,并在浏览器控制台中执行以下代码后:
(function () {
var root = $(document.getElementsByTagName('body'));
var watchers = [];
var f = function (element) {
if (element.data().hasOwnProperty('$scope')) {
angular.forEach(element.data().$scope.$$watchers, function (watcher) {
watchers.push(watcher);
});
}
angular.forEach(element.children(), function (childElement) {
f($(childElement));
});
};
f(root);
console.log(watchers.length);
})();
我发现我只有一个观察者!所以观察者可能不是问题所在。使用此代码,我实现了无限滚动。每个元素都包含图像和文本。问题是,在获得超过200-250个项目后,我的UI开始滞后,即使我有1个观察者。我认为这可能是因为图像尺寸,但在我在Chrome控制台$(".item").html('')
中执行并清除了所有框的内容后,我的UI仍然不顺畅。这个问题不是由太多的DOM元素引起的,因为除了指令所呈现的div之外,我总共只有38个div。如何提高我的应用程序的性能?
编辑:还有一个奇怪的事情,我注意到即使我通过$(".item").remove
从DOM中移除所有元素(在渲染之后),浏览器仍然使用300mb + RAM。
答案 0 :(得分:2)
我会使用 AngularJS Batarang 插件仔细检查观察者的数量,该插件有一个“性能”标签,您可以在其中查看所有手表。
以下是如何使用chrome dev工具分析内存的摘要。
堆分配配置文件:记录随时间的分配
堆快照:记录实际分配的对象
$(".item").html('')
你也可以: