Компоненты Angular - дополнительные привязки
Я хочу создать кучу общего компонента (angular 1.5) с несколькими необязательными связями, которые будут использоваться внутри нескольких приложений.
Я боюсь, что это создаст много ненужных наблюдателей для приложения, которое не использует большинство дополнительных привязок.
Пример:
Объявление компонента:
let dateRangeComponent = {
bindings: {
label: '@',
name1: '@',
name2: '@',
model1: '>?',
model2: '>?',
extra1: '>?'
},
template: `<div ng-if="$ctrl.model1>stuff</div>
<div ng-if="$ctrl.model2>stuff</div>
<div ng-if="$ctrl.extra1>stuff</div>`
};
Пример использования компонента:
<date-rage-component label="Pretty Date" name1="Start" name2="end"/>
Мой вопрос в том, можно ли автоматически отключить все материалы, связанные с неиспользуемыми необязательными связями, зная, что они undefined во время компиляции?
Например, представьте, что я хочу использовать компонент в своем приложении, где он не нуждается в каком-либо необязательном Binding, angular создаст много ненужных наблюдателей, чтобы сохранить ng-if update, когда мы знаем, что они всегда будет ложным.
Я делаю раннюю оптимизацию производительности, когда не нужно или не понимает какую-либо концепцию?
Я, хотя в создании директивы обложки costum, чтобы воспользоваться ленивой компиляцией трансключений в angular 1.5
Что-то вроде этого (псевдокод, не проверен):
<optional-binding-once ng-if="::attrs.model1">
<div ng-if="attrs.model1">
stuff
</div>
</optional-binding-once>
Таким образом, я думаю, что код внутри optional-binding-once будет только скомпилирован, если ng-if истинно, тем самым уменьшив один наблюдатель, если привязка не определена.
(EDIT) Некоторые выводы после некоторых тестов и исследований
Ну, я думаю, нет никакого тривиального решения, чтобы уменьшить количество наблюдателей внутри компонента, когда необязательные привязки не заполнены.
Я провел несколько тестов через фазу $digest angular, чтобы проверить, действительно ли увеличилось количество таких наблюдателей.
Вот мои результаты:
Проверяет, где против худшего сценария, имеющего 888 компонентов с 4 необязательными привязками.
Chrome - без дополнительных привязок (компонент 888, общий наблюдатель 889)
- Всего наблюдателей: 889
- Последний дайджест Время цикла: 0.9950000000026193
- Среднее время для последних 1004 циклов дайджеста: 1.0544920318724353 мс
- начало загрузки dom (400 мс)
Chrome - с дополнительными привязками (компонент 888, 4 необязательных привязки, общий просмотр 4441)
- Всего наблюдателей: 4441
- Последний дайджест Время цикла: 1.1549999999988358
- Среднее время для последних 1001 циклов дайджеста: 1.6851748251747816 мс
- начало загрузки dom (600 мс)
Safari - без дополнительных привязок (компонент 888, общий наблюдатель 889)
- Всего наблюдателей: 889
- Последний дайджест Время цикла: 1.0849999999991269
- Среднее время для последних 530 циклов дайджеста: 1.211632075471664 мс
Safari - с дополнительными привязками (компонент 888, 4 необязательных привязки, общий просмотр 4441)
- Всего наблюдателей: 4441
- Последний дайджест Время цикла: 1.7450000000026193
- Среднее время для последних 588 циклов дайджестов: 2.1167176870748237 мс
Выводы:
В худшем случае время $digest увеличивается на 1 мс. Я не думаю, что этот рост станет узким местом для моей работы приложений. Этот вид наблюдателей будет терпеть неудачу в первом состоянии $digest (value = get (current))! == (last = watch.last) && & && и т.д.), что оказывает небольшое влияние на время обработки, потому что они никогда не меняются или не загрязняют контекст angular!
Ответы
Ответ 1
Я использовал бы тот факт, что свойство template
может быть function (tElem, tAttrs) { ... }
(docs), который возвращает строку для изменения шаблон, основанный на имеющихся атрибутах.
Как я могу это сделать, это использовать jQuery и некоторые пользовательские элементы, чтобы указать, какие части шаблона являются условными.
Вот быстрая шаблонная функция шаблона:
function template($element, $attrs) {
var fullTemplate = $('<div><if-attr name="a"><div ng-if="$ctrl.a"></div></if-attr></div>');
fullTemplate.find('if-attr').each(function() {
if (attrs.hasOwnProperty($(this).attr('name'))) {
$(this).replaceWith(this.innerHTML);
} else {
$(this).remove();
}
});
return fullTemplate[0].outerHTML;
}
Пример вывода
template(null, {a: '1'})
= > "<div><div ng-if="$ctrl.a"></div></div>"
template(null, {b: '1'})
= > "<div></div>"
Известные ограничения
Это отпадает, если вы хотите получить шаблон из URL-адреса (и он не был предварительно добавлен в $templateCache
), но это не похоже на вашу ситуацию.
Если "Минимизировать"
В документации указано, что если template
является функцией, она вводится $element
и $attrs
. Это означает, что если вы уменьшаете свой код, убедитесь, что вы используете безопасный метод для определения имен параметров функции.
например
template: ['$element', '$attrs', function ($elem, $attrs) {
// ...
}],
или
function templateFn($elem, $attrs) {
// ...
}
templateFn['$inject'] = ['$element', '$attrs'];
template: templateFn,
Ответ 2
Еще одно предложение - НЕ создавать общий компонент. Вместо этого отложить бизнес-логику до услуг и создать конкретные компоненты. Пусть потребительский код определяет, какой компонент использовать в зависимости от их потребностей. Если у вас много общего поведения, разделяемого несколькими компонентами, вы можете добавить службу к компонентам, чтобы их повторно использовать. Рассмотрите разделение бизнес-логики на несколько сервисов и используйте иерархический дизайн для повторного использования кода, но с учетом спецификации в зависимости от случая. Нажимайте общий код на абстрактный сервис и распространяйте его на конкретные службы. Внесите конкретные услуги в свои компоненты. Будьте счастливы:).
Ответ 3
Хорошим способом является ответ @GregL, использование другого шаблона с разными атрибутами, но вы также можете использовать ng-attr- [nameCustomAttr] = "value" для дополнительных привязок, см. мой связанный ответ, и таким образом angular используйте тип bindingOnce и проверьте, имеет ли значение attr значение и добавляет или нет атрибут, зависящий от значения.
Для этого необходимо, чтобы attrs оставались на шаблоне директивы/компонента.
Примечание: angularjs создают часы только для переменных, которые появляются в пользовательском интерфейсе.
Хорошо, удачи, надеюсь, это поможет вам в чем-то.