Я создаю сложное угловое приложение, которое имеет бесконечную прокрутку с похожими на марсониум колоннами и изображениями. Я сделал исследование, и я writted своей собственной директивы для визуализации данных для меня:Проблемы с производительностью AngularJS
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);
})();
Я понял, что я получил только 1 Бодрствующего ! Таким образом, наблюдатели могут не быть проблемой. С помощью этого кода я реализовал бесконечную прокрутку. Каждый элемент отображает изображение и текст. Проблема в том, что после получения более 200-250 пунктов мой пользовательский интерфейс начинает отставать, даже если у меня есть 1 наблюдатель. Я думал, что это может быть из-за размера изображения, но после того, как я выполнил на консоли Chrome $(".item").html('')
и очистил содержимое всех ящиков, мой интерфейс все еще не является гладким. Проблема не вызвана слишком большим количеством элементов DOM, потому что у меня есть только 38 разделов, кроме divов, предоставленных директивой. Как я могу увеличить производительность моего приложения?
Редактировать: Также странно, что я заметил, что даже если я удалю все элементы из DOM (после их рендеринга) через $(".item").remove
, браузер по-прежнему использует 300 МБ + ОЗУ.
http://i.imgur.com/dUzx00P.png, всего 1 наблюдатель – Deepsy
Хорошо, хорошо. Вы пытались получить профиль распределения кучи (с помощью инструментов Chrome dev) и моментальный снимок кучи до и после '$ (". Item "). Html ('')', чтобы увидеть, какой объект остается? – Sylvain
Можете ли вы дать мне простое объяснение, как я могу это сделать? – Deepsy