博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
angular脏值检测策略
阅读量:5280 次
发布时间:2019-06-14

本文共 4086 字,大约阅读时间需要 13 分钟。

Angular默认情况下保守,当某个节点发生更改时,每次检查每个组件,如下图

 

我们发现每次变化检测都是从根组件开始,从上往下执行。虽然 Angular 2 优化后的变化检测执行的速度很快,每毫秒几十万次,但我们能否只针对那些有变化的组件才执行变化检测或灵活地控制变化检测的时机呢 ? 答案是有的,接下来我们看一下具体怎么进行优化。

 

先来一个简单的例子:

  app.component.ts

import { Component } from '@angular/core';@Component({  selector: 'app-root',  templateUrl: './app.component.html'})export class AppComponent {  foods = ['Bacon', 'Lettuce', 'Tomatoes'];  addFood(food) {    this.foods.push(food);  }}

  app.component.html

  child.component.ts

import { Component, Input } from '@angular/core';@Component({  selector: 'app-child',  templateUrl: './child.component.html'})export class ChildComponent {  @Input() data: string[];}

  child.component.html

  • {
    { item }}

这是个很简单的例子,父组件改变值,脏值检测到子组件,每当父组件有改变,子组件也跟着改变,如果父组件的输入属性没有变化的话再检测子组件,这是一件没有意义的事,还会增加性能开销,所以就有了脏值检测策略

OnPush策略

 一个简单的例子:

import { Component, Input, ChangeDetectionStrategy } from '@angular/core';@Component({  selector: 'app-child',  templateUrl: './child.component.html',  changeDetection: ChangeDetectionStrategy.OnPush})export class ChildComponent {  @Input() data: string[];}

当上面的例子运行的时候,父组件再给foods push新的值得时候,子组件视图也不会更新,这是因为,在js中,默认对象都是可变的,我们先来看一下下面这个例子

var food={  name:'小龙坎',  from:'成都'  }var fo=food;fo.name='牛肉面';fo.from='兰州';console.log(food===fo);//true

 

通过这个例子,你也许会明白为什么前面的视图没有更新了,让我们再来了解下Immutable .

var food={  name:'小龙坎',  from:'成都'  }var fo=Objec.assign({},food);fo.name='牛肉面';fo.from='兰州';console.log(food===fo);//false

Imutable表示对象不可变,我们修改一个对象的时候新建一个对象,在新对象上做修改。

在Onpush策略源码中,它是这么实现对比的:

function looseIdentical(a, b) {    return a === b || typeof a === 'number' && typeof b === 'number' && isNaN(a) && isNaN(b);}

所以当我们使用OnPush策略时,要使用Imutable对象才能实现实现我们想要的效果

上面的例子改成这种实现,页面会跟着刷新

addFood(food) {  this.foods = [...this.foods, food];}

用OnPush,会大大优化我们项目的性能,

 

          加了OnPush之后

 

 

ChangeDetectorRef

ChangeDetectorRef策略可以完全控制检测。它是通过依赖注入获取对象

import { ChangeDetectorRef } from ‘@angular/core‘;@Component({}) class ChildComponent {    constructor(private cdRef: ChangeDetectorRef) {}}

检测方法有下面几个:

export abstract class ChangeDetectorRef {  abstract markForCheck(): void;  abstract detach(): void;  abstract detectChanges(): void;  abstract reattach(): void;}

  API介绍:

  • markForCheck() - 在组件的 metadata 中如果设置了 changeDetection: ChangeDetectionStrategy.OnPush 条件,那么变化检测不会再次执行,除非手动调用该方法。 

  • detach() - 从变化检测树中分离变化检测器,该组件的变化检测器将不再执行变化检测,除非手动调用 reattach() 方法。

  • reattach() - 重新添加已分离的变化检测器,使得该组件及其子组件都能执行变化检测

  • detectChanges() - 从该组件到各个子组件执行一次变化检测

ChangeDetectorRef.detectChanges()

假如我们的子组件有个刷新按钮,如下

import { Component,         Input,         ChangeDetectionStrategy,         ChangeDetectorRef } from '@angular/core';@Component({  selector: 'app-child',  templateUrl: './child.component.html',  changeDetection: ChangeDetectionStrategy.OnPush})export class ChildComponent {  @Input() data: string[];  constructor(private cd: ChangeDetectorRef) {}  refresh() {    this.cd.detectChanges();  }}

在每次手动刷新的时候,他会更改检测

ChangeDetectorRef.markForCheck()

如果数据是可观察的

app.component.ts

import { Component } from '@angular/core';import { BehaviorSubject } from 'rxjs/BehaviorSubject';@Component({ ... })export class AppComponent {  foods = new BehaviorSubject(['Bacon', 'Letuce', 'Tomatoes']);  addFood(food) {    this.foods.next(food);  }}

 

child.component.ts

import { Component,         Input,         ChangeDetectionStrategy,         ChangeDetectorRef,         OnInit } from '@angular/core';import { Observable } from 'rxjs/Observable';@Component({  selector: 'app-child',  templateUrl: './child.component.html',  changeDetection: ChangeDetectionStrategy.OnPush})export class ChildComponent implements OnInit {  @Input() data: Observable
; foods: string[] = []; constructor(private cd: ChangeDetectorRef) {} ngOnInit() { this.data.subscribe(food => { this.foods = [...this.foods, ...food]; }); }}

 在子组件订阅了它,在每次值变化的时候进行更新检测

ngOnInit() {  this.data.subscribe(food => {    this.foods = [...this.foods, ...food];    this.cd.markForCheck();  });}

 下面三张图来说明观察者检测方式:

 

 

 

 

这时候我们可以脱离的检测,用观察者模式,精准高效的事件了脏值检测,提高整个系统的整体性能。

转载于:https://www.cnblogs.com/nanguabushuohua/p/9067716.html

你可能感兴趣的文章
JavaScript中随着鼠标拖拽而移动的块
查看>>
HDU 1021 一道水题
查看>>
The operation couldn’t be completed. (LaunchServicesError error 0.)
查看>>
php每天一题:strlen()与mb_strlen()的作用分别是什么
查看>>
工作中收集JSCRIPT代码之(下拉框篇)
查看>>
《转载》POI导出excel日期格式
查看>>
code异常处理
查看>>
git - 搭建最简单的git server
查看>>
会话控制
查看>>
推荐一款UI设计软件Balsamiq Mockups
查看>>
Linux crontab 命令格式与详细例子
查看>>
百度地图Api进阶教程-地图鼠标左右键操作实例和鼠标样式6.html
查看>>
游标使用
查看>>
LLBL Gen Pro 设计器使用指南
查看>>
SetCapture() & ReleaseCapture() 捕获窗口外的【松开左键事件】: WM_LBUTTONUP
查看>>
Android 设置界面的圆角选项
查看>>
百度地图api服务端根据经纬度得到地址
查看>>
CSS中隐藏内容的3种方法及属性值
查看>>
每天一个linux命令(1):ls命令
查看>>
根据xml生成相应的对象类
查看>>