2014-02-28 6 views
1

Я создаю сложное угловое приложение, которое имеет бесконечную прокрутку с похожими на марсониум колоннами и изображениями. Я сделал исследование, и я 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 МБ + ОЗУ.

ответ

2

Я бы дважды проверял счет наблюдателей, используя AngularJS Batarang плагин с вкладкой Performance, где вы можете увидеть все часы.


Вот краткое изложение того, как использовать инструменты chrome для профильной памяти.

кучного профиль распределения: распределение записей по времени

  • открытым хром Dev инструменты
  • открыт Профиль Вкладка
  • нажмите профиль распределения кучи
  • нажмите начать
  • делать то, что вам нужно загружать данные в вашу сетку
  • click stop

кучи снимков: записи фактические выделенные объекты

  • открытым хром Dev инструменты
  • открыт Профиль Вкладка
  • нажмите кучного снимок
  • нажмите взять снимок
  • делать то, что вам нужно для загрузки данных в вашу сетку
  • click профили снова на левом верхнем углу
  • кликах Сфотографировать
  • запустить $(".item").html('')
  • профили снова нажмите на верхний левый
  • щелчок Сфотографировать
  • нажмите на одну из 3 профилей с левой стороны и увидеть экземпляры

Вы также можете:

  • нажмите на одном из 3-х профилей слева
  • теперь в верхней строке установите раскрывающееся меню на «comparaison»
  • рядом с опцией «comparaison» выберите, какой снимок можно сравнить с.
+0

http://i.imgur.com/dUzx00P.png, всего 1 наблюдатель – Deepsy

+0

Хорошо, хорошо. Вы пытались получить профиль распределения кучи (с помощью инструментов Chrome dev) и моментальный снимок кучи до и после '$ (". Item "). Html ('')', чтобы увидеть, какой объект остается? – Sylvain

+0

Можете ли вы дать мне простое объяснение, как я могу это сделать? – Deepsy

Смежные вопросы