angular变化检测机制 【default策略,Onpush策略】

目录

angular变化检测的概述 

什么是angular变化检测

触发事件改变的情况

angular 获取变化通知

变化检测策略

 Default:

 Onpush:

需要用到OnPush策略的情况

 例子

参考


angular变化检测的概述 

  1. 首先,数据发生变化
  2. 被NgZone服务捕获
  3. NgZone服务通知Angular有数据发生改变
  4. Angular接收到有数据发生了变化的信号,对组件执行变更监测处理【当组件实例化之后,Angular 就会创建一个变更检测器,它负责传播组件各个绑定值的变化。】

什么是angular变化检测

Angular提供了数据绑定的功能。所谓的数据绑定,就是把组件类中的数据与页面的DOM元素关联起来,当数据发生变化时,Angular能够监测到这些变化,并对其绑定的DOM元素进行相应的更新;反之,当检测到视图上绑定的值发生改变时,则回调对应的绑定函数。【检测视图与模型之间绑定的值是否发生了改变。】

触发事件改变的情况

  • 事件: click,input,submit...
  • 请求服务端数据(XHR)
  • 定时事件,比如setTimeoutsetInterval

上述三种情况都有一个共同点,即这些导致绑定值发生改变的事件都是异步发生的。如果这些异步的事件在发生时能够通知到Angular框架,那么Angular框架就能及时的检测到变化。

angular 获取变化通知

通常,异步事件的发生会导致组件中的数据发生变化,但Angular并不是去捕获对象的变动,而是在适当的时机去检测对象的值是否被改变。这个时机是由NgZone这个服务去掌控的,它会获取整个应用的执行上下文,能够对相关的异步事件的发生、完成、异常等进行捕获,然后驱动Angular的变化检测机制去执行。

Angular接入了ZoneJS,由它监听了Angular所有的异步事件。Zone有一个叫猴子补丁的东西。在Zone.js运行时,就会为这些异步事件做一层代理包裹,也就是说Zone.js运行后,调用setTimeout、addEventListener等浏览器异步事件时,不再是调用原生的方法,而是被猴子补丁包装过后的代理方法。代理里setup了钩子函数, 通过这些钩子函数, 可以方便的进入异步任务执行的上下文。

变化检测策略

 Angular为每一个组件都创建了一个变化监测类的实例,该实例提供了一些方法可以手动管理变化监测。当发生变化时,Angular会从根组件到子组件来监测每个组件是否发生了变化。Angular本身并不知道是哪个组件发生了变化,所以才遍历所有组件进行监测。

但是开发者是知道哪个组件发生了变化,所以可以通过变化监测类的实例提供的方法给这个组件做标记,来通知Angular仅仅监测这个组件所在的路径上的组件就可以了。

 Default:

  •   优点: 每一次有异步事件发生,Angular都会触发变更检测(脏检查),从根组件开始遍历其子组件,对每一个组件都进行变更检测,对dom进行更新
  •   缺点: 有很多组件状态(state)没有发生变化,无需进行变更检测,进行没有必要的变更检测,如果你的应用程序中组件越多,性能问题会越来越明显.

 Onpush:

  •   优点: 组件的变更检测(脏检查)完全依赖于组件的输入(@Input),只要输入值不变,就不会触发变更检测,也不会对其子组件进行变更检测,在组件很多的时候会有明显的性能提升
  •   缺点:必须保证输入(@Input)是不可变的(可以用Immutable.js解决),就是每一次输入变化都必须是一个新的引用(js中object,array的可变性).

 

需要用到OnPush策略的情况

NgZone通知框架在异步操作发生时执行变更检测,因此当mousemove事件触发时它也会触发变更检测。我们可能不希望每次触发mousemove时都执行更改检测,因为它会降低我们的应用程序速度并导致非常糟糕的用户体验。

 例子

export class Star {
  constructor(public firstName: string, public lastName: string) {}
} // 模型

父组件:

{{ star | json }}
<button type="button" (click)="changeStar()">改变明星属性</button>
<button type="button" (click)="changeStarObject()">改变明星对象</button>
<app-child [star]="star" ></app-child>
 star: Star = new Star('周', '杰伦');
  changeStar() {
    this.star.firstName = '吴';
    this.star.lastName = '彦祖';
    console.log('更改属性');
  }
  changeStarObject() {
    this.star = new Star('刘', '德华');
    console.log('更改对象');
  }

子组件:

<span>{{star.firstName}} {{star.lastName}}</span>
changeDetection: ChangeDetectionStrategy.OnPush  // 使用Onpush策略就加这句话,使用default就不加这句话 ,在@Component({})里添加
@Input() star: any;

截图如下:

  • default策略的情况:

 第一次渲染

  点击第一个更改属性按钮

 点击第二个更改对象按钮

default策略的情况下,父组件,子组件页面都正常地更新了。

  • OnPush策略的情况:

其它都相同,不同的地方在于点击第一个更改属性按钮后:父组件更新了,子组件并未更新。

我们明确地告诉Angular我们的组件只依赖于它的输入,并且它们都是不可变的。然后,Angular假定子组件没有更改,并将跳过对该组件的检查。因为我们没有强制Star对象是不可变的,所以最终我们的模型与视图不同步. 

点击第二个更改对象按钮,子组件视图更改的原因:创建了新实例,更改检测知道Star对象已更改,会继续进行全局的检查。

参考

https://www.cnblogs.com/hanshuai/p/9362660.html  (是一个系列,有3篇)

 

映射类型(keyof, Pick<T, K>)

svg 可自适应 描边 圆锥渐变

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值