Компоненты 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 создают часы только для переменных, которые появляются в пользовательском интерфейсе.

Хорошо, удачи, надеюсь, это поможет вам в чем-то.