通用角度组件 - 可选绑定

Lui*_*ves 20 javascript angularjs angularjs-directive

我想创建一堆通用组件(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>`
};
Run Code Online (Sandbox Code Playgroud)

组件使用示例:

<date-rage-component label="Pretty Date" name1="Start" name2="end"/>
Run Code Online (Sandbox Code Playgroud)

我的问题是,是否可以自动查看与未使用的可选绑定相关的所有内容,知道它们在编译时未定义?

例如,想象一下我想在我的应用程序中使用一个组件,它不需要任何可选的Binding,angular会创建许多不必要的观察者来保持ng-if更新,当我们知道它们总是假的时候.

我是否在不需要时进行早期性能优化或误解任何概念?

我虽然在创建一个costum包装器指令,以利用角度1.5中的延迟转换编译

像这样的东西(伪代码,未经过测试):

<optional-binding-once ng-if="::attrs.model1">
  <div ng-if="attrs.model1">
      stuff
  </div>
</optional-binding-once>
Run Code Online (Sandbox Code Playgroud)

通过这种方式,我认为只有在ng-if为真时才会编译optional-binding-once中的代码,因此如果没有定义绑定,则会减少一个观察者.

(EDIT)经过一些测试和研究后的一些结论

嗯,我想当没有填充可选绑定时,没有一个简单的解决方案来减少组件内的观察者数量.

我通过角度的$ digest阶段运行了一些测试,以检查这类观察者的数量增加是否真的有问题.

这是我的结果:

针对最坏情况的测试,其具有888个具有4个可选绑定的组件.

Chrome - 没有可选绑定(888组件,总观察者889)

  • 总观察者:889
  • 最后摘要周期时间:0.9950000000026193
  • 最后1004个摘要周期的平均时间:1.0544920318724353 ms
  • 开始dom加载(400ms)

Chrome - 可选绑定(888个组件,4个可选绑定,总观察者4441)

  • 总观察者:4441
  • 最后的摘要周期时间:1.1549999999988358
  • 最后1001个摘要周期的平均时间:1.6851748251747816 ms
  • 开始dom加载(600ms)

Safari - 没有可选绑定(888组件,总观察者889)

  • 总观察者:889
  • 上一个摘要周期时间:1.0849999999991269
  • 最后530个摘要周期的平均时间:1.211632075471664 ms

Safari - 可选绑定(888个组件,4个可选绑定,总观察者4441)

  • 总观察者:4441
  • 最后摘要周期时间:1.7450000000026193
  • 过去588个摘要周期的平均时间:2.1167176870748237 ms

结论:

在最坏的情况下,$ digest时间将增加1ms.我不认为这种上升会成为我的应用程序性能的瓶颈.这种观察者将在第一个$ digest条件(value = get(current))!==(last = watch.last)&& etc ...)中失败,因此在处理时间上影响很小,因为他们从不改变或获得角度上下文脏!

Gre*_*egL 1

我会利用该template属性可以是function (tElem, tAttrs) { ... }文档)这一事实来根据存在的属性修改模板。

我执行此操作的方法是使用 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;
}
Run Code Online (Sandbox Code Playgroud)

样本输出

template(null, {a: '1'}) => "<div><div ng-if="$ctrl.a"></div></div>"
template(null, {b: '1'}) =>"<div></div>"

已知限制

如果您想从 URL 获取模板(并且它没有预先填充在$templateCache),那么这种情况就会失败,但这似乎不是您的情况。

如果缩小

文档指出 iftemplate一个函数,它被注入$element$attrs。这意味着,如果您要缩小代码,请确保使用缩小安全的方法来指定函数参数名称。例如

template: ['$element', '$attrs', function ($elem, $attrs) { 
    // ...
}],
Run Code Online (Sandbox Code Playgroud)

或者

function templateFn($elem, $attrs) { 
    // ...
}
templateFn['$inject'] = ['$element', '$attrs'];

template: templateFn,
Run Code Online (Sandbox Code Playgroud)