Как ускорить приложение AngularJS?
У меня есть приложение AngularJS со страничной сеткой (два вложенных ng-repeat). На одной странице имеется примерно 25x40 элементов ввода. В начале, который сделал 1000 привязок, производительность пейджинга была приемлемой.
Но тогда сложность страницы растет: динамические классы, различные контекстные меню, условный контент для каждой ячейки сетки. И с оценкой 6000 привязок (6 на каждый элемент ввода) пейджинг стал непригодным для использования.
Мой вопрос: как я вообще подхожу к проблемам производительности в AngularJS?
Очевидным первым шагом является измерение. Но результаты Chrome Profiler не говорят мне об этом, далеко не зная, как действовать.
Self Total Function
-----------------------------------------------------------------
24 ms 2.79 s angular.js:7997 Scope.$digest
1 ms 1 ms controllers.js:365 setViewportData
16 ms 692 ms angular.js:13968 ngRepeatWatch
8 ms 22 ms angular.js:6439 extend.literal
9 ms 1.22 s angular.js:14268 ngSwitchWatchAction
16 ms 45 ms angular.js:12436 ngModelWatch
0 621 ms angular-ui-4.0.js:264 initDateWidget
0 13 ms angular.js:12859 ngClassWatchAction
0 70 ms angular.js:14184 ngStyleWatchAction
1 ms 5 ms angular-ui-4.0.js:261 getOptions
0 16 ms angular.js:579 copy
0 1 ms angular.js:4558 interpolateFnWatchAction
1 ms 2 ms angular.js:5981 token.fn.extend.assign
0 37 ms angular.js:8151 Scope.$eval
1 ms 1 ms angular.js:6137 extend.constant
14 ms 16 ms angular.js:651 equals
1 ms 1 ms angular.js:4939 $interpolate.fn
Кроме того, есть ли вероятность, что "Object.observe()" ускорит работу в будущем (игнорируя "initDateWidget", это, очевидно, другая тема)?
Ответы
Ответ 1
То, что вы можете сделать, ускорит ваше приложение Angular, самое главное - уменьшить эти привязки, где вы можете. Один из способов сделать это - создать директиву, которая построила таблицу для вас с помощью DOM-манипуляции вместо использования ng-повторов. Это уменьшит количество общих часов, которые вы должны обработать, и сделайте этот дайджест намного быстрее.
Я знаю, что это уродливо, но Angular не предназначено для установки более 3000 привязок. Поскольку он делает дайджест, и это не шаблон наблюдателя, он действительно замедляет работу, поэтому многие настроены.
Вы даже можете использовать гибридный подход, в котором вы все еще использовали ng-repeat, но все значения были помещены в DOM с прямой обработкой DOM из пользовательской директивы, что позволило избежать всех привязок.
Ответ 2
Если вы этого еще не сделали, установите модуль AngularJS Chrome Batarang, который поможет вам определить, какое из ваших привязок вызывает у вас горе. https://chrome.google.com/webstore/detail/angularjs-batarang/ighdmehidhipcmcojjgiloacoafjmpfk?hl=en
Как следует из другого ответа, то, что вы ищете, вероятно, является небольшим случаем установки бесконечного прокрутки для вашей таблицы, где модель, с которой вы связываете, является подмножеством, отображаемым на экране.
Компонент ng-grid реализует это и может стоить взглянуть на то, чтобы использовать его напрямую или украсть технику. http://angular-ui.github.com/ng-grid/
Ответ 3
Ресурс
Этот пост о производительности angularJS в больших списках имеет хороший обзор параметров, которые вы имеете для настройки производительности.
Выше ответы (кроме плагина Batarang) также упоминаются внутри. Это всего лишь обзор советов в этой статье.
Уменьшить данные с помощью limitTo (разбиение на страницы)
Одно из наиболее очевидных решений - уменьшить количество привязок, уменьшив количество элементов в вашем представлении. Разбиение данных может производиться с помощью фильтра limitTo
на ng-repeat
.
Пример Как повысить производительность ngRepeat над огромным набором данных (angular.js)? В этой статье также есть пример jsbin, связанный.
Также не забудьте использовать встроенный метод для предоставления данных, так как это будет оцениваться на каждом $digest.
<li ng-repeat="item in filteredItems()"> // Bad idea, since very often evaluated.
<li ng-repeat="item in items"> // Way to go!
Удалить привязки с помощью bindonce
Еще одно очевидное решение - удалить привязки для определенных элементов. Конечно, это означает, что обновления больше не будут отображаться в представлении.
Решение bindonce делает гораздо больше, чем просто удаление привязки в 2 способа. В основном он ожидает, что значение будет привязано один раз до удаления привязки. Лучше всего читайте сами. Подробнее см. проект bindonce.
В приведенной выше статье есть также информация о шаблоне, работающем с 2 списками. Один для визуализации и один как источник данных.
Использовать ng-сетку
Ng-grid
имеет то преимущество, что он отображает только те элементы, которые в настоящее время видны. Подробнее на http://angular-ui.github.io/ng-grid/.
Аналогичный ng-if
полностью удаляет скрытые элементы из дерева DOM, а ng-show
сохраняет их только на месте, но скрыт. Примите во внимание, что ng-if
поместит копию оригинала (оригинал - это ключ, а не те изменения), который появился, когда он будет показан снова.
Советы по фильтрации
В статье также есть несколько полезных советов для фильтрации списков.
Как и использование ng-show
, чтобы скрыть отфильтрованные элементы, так как этот способ не может быть создан подстроем.
И еще один метод, называемый "debounce user input". Последняя опция - подождать с фильтрацией, пока пользователь не перестанет печатать. Включая пример jsfiddle.
Подробнее
Дополнительные советы можно найти в связанной статье. Там есть ресурсы, которые должны быть хорошей отправной точкой. Я считаю, что самые очевидные и быстрые победы перечислены здесь.
Еще одна приятная запись Как работает привязка данных в AngularJS?
Ответ 4
Немного поздно, но, возможно, это сработает для вас:
https://github.com/Pasvaz/bindonce
Вы можете использовать его в тех привязках, которые не предназначены для изменения, поэтому $digest больше не будет обрабатывать их.
Ответ 5
В angular 1.3 и более вы можете связать один раз, используя:: не нужно использовать другие 3-сторонние js
<li ng-repeat="item in :: items">
Это хорошо, если элементы не будут меняться, поэтому вы можете связать их один раз
Ответ 6
Я столкнулся с проблемами производительности, когда количество слушателей превысило 1000+ в компоненте сетки данных.
Я решил эти проблемы, используя директиву, которая строит мое представление с помощью response.js.
директива выставила функцию обновления.
каждый раз, когда данные изменялись (в контроллере), функция обновления вызывала директиву, а затем механизм реакции .js эффективно выполнял рендеринг.
Я знаю его большие накладные расходы, чтобы использовать вторую основную структуру внутри проекта angular, и это не настоящая манера связывания данных. но его работа намного быстрее.
В конце концов я прекратил использование angular.js и перешел на response.js + FLUX. я думаю, что это лучше, но я знаю, что его нелегко перейти от angular, но это того стоит.
Angular директива, которая использует response.js
Ответ 7
Ограничение количества часов может длиться долго. Вот краткое описание методов, которые эффективны для уменьшения количества часов
http://www.syntaxsuccess.com/viewarticle/547a8ba2c26c307c614c715e
Ответ 8
У меня были проблемы с производительностью с ng-сетью с большими данными, она была решена путем замены Angular Grid. Демо на этом сайте показывает, что он легко управляет 100 000 строк.
Ответ 9
Я боролся с этим несколько недель. Я обнаружил, что две вещи существенно изменили:
(i) ОДНОВРЕМЕННЫЕ РАЗМЕРЫ: используйте одноразовые привязки, где вы можете; а также
(ii) DEBOUNCE: для ввода, который мне не нужен, сразу же размножается, но может ждать 250 мс, установите настройку debounce. Это сделало НЕВЕРОЯТНОЕ отличие от моей большой таблицы ng-repeat. Я не могу подчеркнуть, насколько эффективна настройка debounce. (см. здесь https://docs.angularjs.org/api/ng/directive/ngModelOptions)
Ответ 10
bject.observe() - это предлагаемый механизм для передачи истинной привязки данных к браузеру. Он предоставляет механизм наблюдения за изменениями объектов и массивов, уведомляя других о мутациях, сделанных для этих объектов.
<!DOCTYPE html>
<html>
<head>
<base target="_blank">
<title>Object.observe()</title>
<link rel="stylesheet" href="../css/main.css" />
</head>
<body>
<div id="container">
<h1><a href="https://shailendrapathakbits.wordpress.com/" title="code_lab_by_shail ">code_lab_by_shail</a> Object.observe()</h1>
<p>An object <code>o</code> is created and <code>Object.observe()</code> is called on it.</p>
<p>Three changes are made to <code>o</code> and <code>Object.observe()</code> records these changes as shown below.</p>
<p>Use the console to find out what happens if you make further changes to <code>o</code>: it defined in global scope.</p>
<p>Call <code>Object.unobserve(o, observer)</code> to stop observing changes.</p>
<p id="data" style="font-size: 14px;"></p>
<script src="js/main.js"></script>
<a href="https://github.com/shailendra9/objectobserver/blob/master/index.html" title="View source for this page on GitHub" id="viewSource">View source on GitHub</a>
</div>
<script src="../js/lib/ga.js"></script>
</body>
</html>
Ответ 11
Вы также можете улучшить производительность в целом Отключение отладочных данных