【Angular】`ChangeDetectionStrategy.OnPush`の効果を確認してみる #Angular

您所在的位置:网站首页 网上做的项目怎么找 【Angular】`ChangeDetectionStrategy.OnPush`の効果を確認してみる #Angular

【Angular】`ChangeDetectionStrategy.OnPush`の効果を確認してみる #Angular

2024-07-15 01:51:17| 来源: 网络整理| 查看: 265

はじめに

Angularのパフォーマンス改善で「ChangeDetectionStrategy.OnPushを指定する」というのをよく見るが、これを設定するとどんな良いことがあるのか、を実際に見える形で確認したかったので試した。 今回はその結果を共有していく。

ChangeDetectionとは

これに関しては@lacolacoさんの記事がとても参考になる(なった)ので、そちらを確認いただきたい。 Angular2のChange Detectionについて Angular2はいかにしてオブジェクトの変更を監視しているのか 日本語訳:Angular 2 Change Detection Explained

・Change Detectionとはモデルの変更を検知し、UIに反映することである ・Angularはあらゆる非同期処理の後にChange Detectionを行う(Zoneを使って) ・変更を検知する際にはオブジェクトの参照が変わったかどうかが重要である ・Immutableを使えばAngularが変更を検知しやすくなる ・OnPushでChange Detectionをコントロールできる

ChangeDetectionStrategy.OnPushとはChangeDetectionを走らせる下層のコンポーネントを絞る機能

AngularはデフォルトではどのコンポーネントもChangeDetectionを走らせる設定になっている。 これでは変更する必要のないコンポーネントまでもチェックする必要があり、その数が多いとパフォーマンス低下に繋がる。そこでチェックする必要のないコンポーネントを減らせればその分パフォーマンスの向上に繋がる。そのチェックするかどうかを決められる設定がOnPushというわけだ。(正確にはそのコンポーネントからではなく、そこから下のコンポーネントへのチェックを無くせる。)

ChangeDetectionの確認はngDoCheck()で出来る

Angular - DoCheck

A callback method that performs change-detection, invoked after the default change-detector runs. See KeyValueDiffers and IterableDiffers for implementing custom change checking for collections.

実際に確認するアプリの構成

AppComponentがそれぞれ@Input()経由でStoreListComponent, FruitsListComponentには配列、UserComponentにはStringの値を渡す。 2層目では配列なら3層目のコンポーネントに1つ1つ要素を渡し、UserComponentであればAppComponentから受け取った値に文字列を連結させて3層目のコンポーネントに渡す。 AppComponent, StoreListComponentでのみ値を変更するイベントを用意し、それぞれどの層のどのコンポーネントにChangeDetectionが走るのかをngDoCheck()で確認する狙い。 detect-change (1).png

ソースコード

※StoreListとFruitsListおよびそれらのItemコンポーネントは実装がほぼ同じなのでStoreListのみ。 全体のソースコードはこちらから。

app.component このコンポーネントで各層のコンポーネントの値を書き換える。 consoleから確認できるよう各Clickイベントでログを表示するようにした。 app.component.ts import { ChangeDetectionStrategy, Component, DoCheck } from '@angular/core'; import { Store } from './modules/store-list/store-list.component'; import { Fruits } from './modules/fruits-list/fruits-list.component'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'], // changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.Default, }) export class AppComponent implements DoCheck { public storeList: Store[] = [ { name: '渋谷店', isFavorite: true }, { name: '新宿店', isFavorite: false }, { name: '豊洲店', isFavorite: false }, ]; public fruitsList: Fruits[] = [ { name: 'オレンジ' }, { name: 'ブドウ' }, { name: 'バナナ' }, { name: 'メロン' }, ]; public userName = 'John'; public title = 'angular-change-detect'; ngDoCheck(): void { console.log('AppComponent-DoCheck'); } /** * EventだけでChangeDetectionが走るのかを確認する */ public consoleLog() { console.log('AppComponentのconsoleLog()'); console.log('event'); } /** * AppComponentの値だけを変更してChangeDetectionが走るのかを確認する */ public changeTitle() { console.log('AppComponentのtitleをchange'); this.title = 'Title updated'; } /** * UserComponentの値を変更する */ public changeUserName() { console.log('AppComponentからuserNameをchange'); this.userName = 'Lucy'; } /** * StoreListに要素を追加する */ public addStore() { console.log('AppComponentからStoreListに追加'); this.storeList.push({ name: '飯田橋店', isFavorite: false }); } /** * StoreListのコピーを作成、それに要素を追加して新しい配列を格納する */ public addStoreNewArray() { console.log('AppComponentから新しいStoreList配列を格納'); const currentStoreList = [...this.storeList]; this.storeList = [...currentStoreList, { name: '飯田橋店', isFavorite: false }]; } } app.component.html {{title}} ConsoleLog Change Title Add Store Add Store New Array Change User Name

store-list.component 子コンポーネントでEventが発生してもルートコンポーネントからChangeDetectionが走るのかどうかを確認するため、ここだけClickイベントを実装している。 store-list.component.ts import { ChangeDetectionStrategy, Component, DoCheck, Input } from '@angular/core'; export interface Store { name: string; isFavorite: boolean; } @Component({ selector: 'app-store-list', templateUrl: './store-list.component.html', styleUrls: ['./store-list.component.scss'], // changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.Default, }) export class StoreListComponent implements DoCheck { @Input() storeList: Store[]; constructor() {} ngDoCheck(): void { console.log('StoreListComponent-DoCheck'); } public consoleLog() { console.log('StoreListからconsoleLog()'); console.log('Event in StoreListComponent'); } } store-list.component.html

Store List

Add Store List In StoreListComponent

user.component UserComponentでは@Input()の値が変更されたとき挨拶の文言を結合して子コンポーネントに送るようにしている。 user.component.ts import { ChangeDetectionStrategy, Component, DoCheck, Input, OnChanges } from '@angular/core'; @Component({ selector: 'app-user', templateUrl: './user.component.html', styleUrls: ['./user.component.scss'], // changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.Default, }) export class UserComponent implements OnChanges, DoCheck { @Input() userName: string; public hello = ''; constructor() {} ngOnChanges(): void { this.hello = `Hello ${this.userName}`; } ngDoCheck(): void { console.log('UserComponent-DoCheck'); } } user.component.html

Hello, {{userName}}

user-child.component user-child.component.ts import { Component, DoCheck, Input } from '@angular/core'; @Component({ selector: 'app-user-child', templateUrl: './user-child.component.html', styleUrls: ['./user-child.component.scss'], }) export class UserChildComponent implements DoCheck { @Input() hello: string; constructor() {} ngDoCheck(): void { console.log('UserChildComponent-DoCheck'); } } user-child.component.html

user-child: {{hello}}

全コンポーネントがChangeDetectionStrategy.Defaultの場合

赤枠がAppComponentのClickイベント、青枠がStoreListComponentのClickイベント。 どちらも全てのコンポーネントのChangeDetectionが走ってしまっていることがわかる。 スクリーンショット 2020-02-06 1.39.03.png

さっきの図で表すとこんな感じ。 全ての階層のコンポーネントでChangeDetectionが走っている。 ちなみにAppComponentのどのClickイベントでもこうなる。 detect-change (2).png

2層目のコンポーネントでOnPushを設定した場合

赤枠がAppComponentのtitleを変更、青枠がStoreListに要素を追加、緑枠がStoreListを新しい配列(新しい参照)にしたとき。 AppComponentのtitle変更はStoreListに影響はないので、StoreListItemのChangeDetectionが走っていないことが確認できる。 またStoreListへの要素追加ではStoreListItemのChangeDetectionが走らず、StoreListの参照を変更した場合はStoreListItemのChangeDetectionが走っていることが確認できる。 このことからOnPushを設定した場合、オブジェクトの値であれば参照が変更されるとChangeDetectionが走ることがわかる。 スクリーンショット 2020-02-06 1.56.58.png StoreListのデータに関係のない、または参照が変更されないとOnPushを設定したコンポーネントよりも下層のコンポーネントのChangeDetectionが走らない。 detect-change (3).png 一方で参照を変更すると、OnPushを設定したコンポーネントの下層のみにChangeDetectionを絞ることができる。FruitsListItemにはChangeDetectionが走ってない。複数のリストを表示する、例えばダッシュボード画面のような構成でかなり効果的なのかも…。 detect-change (4).png

(余談)プリミティブな値を変更した場合

AppComponentからuserNameの変更イベントを2度走らせてみた。(1度目が赤枠、2度目が青枠。) 1度目は値が変更されたので、UserChildComponentのChangeDetectionが走っている。 2度目は1度目と同じ値で変更したので値自体は変わらない。するとUserChildComponentのログが表示されなかったので、UserChildComponentのChangeDetectionが走ってないことが確認できる。 このことからプリミティブな値は変更が無ければChangeDetectionが走らないことがわかる。 スクリーンショット 2020-02-06 2.14.56.png

さいごに

今回はChangeDetectionの効果を可視化してみた。 ChangeDetectionStrategy.OnPushを設定することでChangeDetectionの無駄を省くだけでなく、オブジェクトをImmutableを半強制的に扱わせられることもわかった。(半強制的なのはImmutableでなくても自分でChangeDetectionするメソッドを呼べるため。) ダッシュボード画面のように複数のオブジェクトを表示するようなときにこのChangeDetectionStrategy.OnPushを設定すると幸せになるかもしれない。

参考 Angular2のChange Detectionについて Angular2はいかにしてオブジェクトの変更を監視しているのか 日本語訳:Angular 2 Change Detection Explained angular-change-detection-example


【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭