Angular Pipe 在 嵌套对象上的非预期行为分析

发布时间:2019-06-03 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了Angular Pipe 在 嵌套对象上的非预期行为分析脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

Angular PiPE 在 嵌套对象上的非预期行为分析

场景

在工作中,存在一个嵌套对象,需要展示嵌套对象内层的一些信息,于是写了个Pipe 来处理,但是发现当嵌套的对象发生变化时,pipe 不会重新执行。例如有下面一个数据。

VAR feer = {
    name: 'joe',
    skills: [
        {
            name:'js'
        },
        {
            name: 'ts'
        }
    ]
}

我们想要的结果是把skills 里面的name 全部展示出来,以, 分割。

// component
export class AppComponent {
  PRivate skills = ['css', 'htML', 'java', 'gulp']
  name = 'Angular 6';
  feer = {
    name: 'joe',
    skills: [
      {
        name: 'js'
      },
      {
        name: 'ts'
      }
    ]
  }

  add() {
    const skill = this.skills.shift();
    if (skill) {
      this.feer.skills.push({
        name: skill
      })
    }
  }
}
// html
{{ feer.skills | defaultPure }}
// Pipe
import { Pipe, PipeTransform } From '@angular/core';

@Pipe({
    name: 'defaultPure'
})

export class DefaultPurePipe implements PipeTransform {
    transform(feer:any): string {
        return feer.skills.map((v)=>v.name).join(',');
    }
}

在这种情况下,如果调用add 引起 skills 发生变化,pipe 不会重新计算,显示的还是初始值 js,ts

问题

这里存在一个问题,对于上面????例子中存在的嵌套结构,在 skills 变化的时候 ,transform 并没有重新执行。这里推测可能是 内部检测时候并不会做 deep-change-detection (也就是不会关注 skills 里的变化),最终导致了上面的问题: skills 发生了变化,但 pipe 并没有重新执行计算变更输出结果。

下面是摘自官网的一段话:

Angular executes a pure pipe only when it detects a pure change to the input value. A pure change is either a change to a primitive input value (String, Number, Boolean, Symbol) or a changed object reference (Date, Array, Function, Object).

Angular ignores changes within (composite) objects. It won't call a pure pipe if you change an input month, add to an input array, or update an input object property.

pipe 忽略了 对象内部复合对象的变动(如例子中的 skills ), angular 不会做深度检查,当我们调用 add 方法时候,往 skills 数组push 里一个对象,对于 angular 来说, skills 是“未”发生变化的,因为引用是一样的。

解决方案

@Pipe 的 decorator 中除了name 还有一个叫 pure 类型为 booleanmetadata官方解释如下

If Pipe is pure (its output depends only on its input.) Normally pipe's transform method is only invoked when the inputs to pipe's transform method change. If the pipe has internal state (it's result are dependant on state other than its arguments) than set pure to false so that the pipe is invoked on each change-detection even if the arguments to the pipe do not change.

大意是 pipe 仅在输入发生改变的时候会再次执行 transform 方法。但是如果 pipe 有一个内部状态,并且输出依赖于这个内部状态,那么将 pure 设置为 false 以便在每次 change-detection (数据更新检测) 时候执行 transform即使输入的数据并没有改变。

对于pure, 默认值为 true ,如果设置为 false ,则可以将上面的功能实现出来。但是同时要注意一个问题,一个 impurepipe (即 pure = false ) 会经常被调用,如果有大量运算,则可能影响用户体验 。

同样看一段官网的解释:

Angular executes an impure pipe during every component change detection cycle. An impure pipe is called often, as often as every keystroke or mouse-move.

对于 impurepipeangular 会在每次 component 的 变化检测周期里调用执行,甚至一次按键、一次鼠标事件都会触发 pipe 的执行。

最终,对于上述的问题,只需修改 pipe 的代码即可。

@Pipe({
    name: 'defaultPure',
    pure: false
})

export class DefaultPurePipe implements PipeTransform {
    transform(feer:any): string {
        return feer.skills.map((v)=>v.name).join(',');
    }
}

完结

对于上述问题,表面上来说加一下 pure 即可,对于深层次来说,涉及到了 angular 内部的一些工作原理。但是话说回来,目前仅仅研究到这种方案来处理,实际上应该还会有其他的解决方案,大胆猜测可以利用 change-detection 的一些钩子来处理,待研究好了再记录一下。

之前在遇到这个问题的时候,也是一脸懵逼的找答案,殊不知答案就在文档上写的清清楚楚。 ????‍♀️~~~

BTW,其实在 vue 中也存在了一个类似的问题, 为了性能等的考虑,不会对复合对象做深度@R_126_1667@。而 Vue的做法则简单粗暴一些:重新装饰数组方法。 具体可以查看 Vue源代码

脚本宝典总结

以上是脚本宝典为你收集整理的Angular Pipe 在 嵌套对象上的非预期行为分析全部内容,希望文章能够帮你解决Angular Pipe 在 嵌套对象上的非预期行为分析所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。