Подтвердить что ты не робот

Angularjs ng-model внутри ng-repeat имеет низкую производительность

У меня проблема с производительностью angular в следующем сценарии:

<div ng-repeat="a in array">
  <input ng-model="something">
</div>

Я написал код в моем контроллере, который в ng-click меняет массив на наличие другого набора объектов. Проблема в том, что если массив имеет приличное количество объектов, клик не так чувствителен, как хотелось бы (короткая задержка).

После некоторого исследования я заметил, что $digest занимает довольно много времени после того, как я изменил массив в ng-click. Поэтому я создал этот короткий тестовый код, чтобы воспроизвести его.

Реальный сценарий приложения таков: у меня есть таблица, в которой каждая строка представляет собой редактируемый объект, и у каждого объекта есть много разных полей, которые я хочу редактировать. Таким образом, всякий раз, когда я нажимаю на строку в таблице, есть еще один html, который имеет все те ng-repeat с разными input в свойствах моего объекта.

Есть ли у кого-нибудь идея, как сделать это более эффективным?

Спасибо

4b9b3361

Ответ 1

Как правило, плохая идея иметь слишком много элементов ввода на одной странице. Вот почему профессиональные редакторы сетки данных выбирают возможность редактирования только одной строки данных одновременно либо в отдельном всплывающем окне, либо в строке. Даже когда он используется в строке, объекты вводятся "на лету".

Элемент ввода просто слишком тяжелый, чтобы его слишком много на одной странице. В прошлом я делал те же ошибки, пытаясь реализовать сетку данных, где все редактируемые поля были введенными элементами с самого начала. Кроме того, вам нужно сохранить привязку к модели live angular, которая добавляет служебные данные о производительности.

Один из самых простых способов сделать это в вашем случае - реализовать директиву, которая отображается как элемент span до тех пор, пока не будет нажата, и не замените элемент ввода на событие click. Другая альтернатива - иметь оба и переключать их стиль видимости. Последнее, вероятно, еще проще в рамках директивы angular, но не настолько эффективно, возможно.

Также следите за другими связями, которые у вас есть. Когда речь идет о сетях данных, это становится важным. В angular 1.3 теперь вы можете использовать синтаксис "::" для одноразовых привязок, что также может помочь.

Ответ 2

Если я правильно понимаю ваш вопрос, вы испытываете блокировку ui, которая делает ваш опыт изменчивым. Сколько предметов в вашей коллекции? Если я не ошибаюсь, ng-repeat является синхронным, как можно увидеть здесь: https://github.com/angular/angular.js/blob/master/src/ng/directive/ngRepeat.js#L361

Таким образом, вы просто не сможете отображать сотни/тысячи/и т.д. записей без блокировки пользовательского интерфейса с помощью существующего способа ng-repeat. Единственное решение - пойти с асинхронным решением и отобразить немного коллекции за раз. К сожалению, я не видел асинхронный ng-repeat (можно существовать, вы должны искать его или реализовывать сами и давать его нам).

К счастью, вы можете использовать свойство limitTo ng-repeat как взломать что-то подобное. Если у вас есть limitTo: num, где num = 5, тогда будут отображаться только первые 5 записей. Если вы установили num = 7, то он сохранит 5 уже обработанных записей и отобразятся только 6-й записи и 7-я запись.

Итак, чтобы сделать несколько тысяч записей, вам нужно что-то вроде этого, которое изменит limitTo асинхронно:

<div ng-repeat="a in array | limitTo:tick">

...

var repeatAsyncHack = function() {
    $scope.$digest();
    sum += +new Date() - t;
    if($scope.tick < numOfObjects) {
        $scope.tick+=tickAmount;
        requestAnimationFrame(repeatAsyncHack);
    } else {
        $('#results').prepend(
            $("<div>" + 
              numOfObjects + ' objects test took: ' + sum +
              "ms</div>"));
    }
}

Я обновил вашу демонстрацию на http://jsfiddle.net/qrJG3/15/

Конечно, есть минусы этого, поскольку общее время рендеринга намного длиннее. Это просто компромисс, чтобы сделать приложение более отзывчивым.

Пожалуйста, поправьте меня, если я неправильно понял, к чему вы клоните.

Ответ 3

Хорошо, если вы создаете элементы DOM на лету, будет задержка.

Если элементы уже находятся на странице, и вы просто спрячете их до своего времени, это будет обычно намного быстрее.

Еще один аспект, с которым вы могли бы работать, - это чувственная отзывчивость и реальная отзывчивость. Сначала вы можете показать некоторый статический html, а затем заменить его на фактические элементы. Пользователь будет получать немедленные результаты при создании реальных результатов.

Изменить

Позволяет сравнить сгенерированный HTML с и без ng-model

С моделью

<div ng-repeat="a in array" class="ng-scope">
   <input ng-model="a.qqqq" class="ng-pristine ng-valid">
</div>

Плюс-манипулятор на входе.

Без модели

<div ng-repeat="a in array" class="ng-scope">
     <input>
</div>

И никакой обработчик событий.

Вы можете провести глубокое исследование с использованием отладочной версии Angular, чтобы увидеть, что было сделано при добавлении ng-model.

Причина, по которой требуется больше времени, очевидна - Angular делает больше.