【Angular】`ChangeDetectionStrategy.OnPush`の効果を確認してみる #Angular |
您所在的位置:网站首页 › 网上做的项目怎么找 › 【Angular】`ChangeDetectionStrategy.OnPush`の効果を確認してみる #Angular |
はじめに
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()で確認する狙い。
※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 StoreListComponentuser.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が走ってしまっていることがわかる。
さっきの図で表すとこんな感じ。
全ての階層のコンポーネントでChangeDetectionが走っている。
ちなみにAppComponentのどのClickイベントでもこうなる。
赤枠がAppComponentのtitleを変更、青枠がStoreListに要素を追加、緑枠がStoreListを新しい配列(新しい参照)にしたとき。
AppComponentのtitle変更はStoreListに影響はないので、StoreListItemのChangeDetectionが走っていないことが確認できる。
またStoreListへの要素追加ではStoreListItemのChangeDetectionが走らず、StoreListの参照を変更した場合はStoreListItemのChangeDetectionが走っていることが確認できる。
このことからOnPushを設定した場合、オブジェクトの値であれば参照が変更されるとChangeDetectionが走ることがわかる。
AppComponentからuserNameの変更イベントを2度走らせてみた。(1度目が赤枠、2度目が青枠。)
1度目は値が変更されたので、UserChildComponentのChangeDetectionが走っている。
2度目は1度目と同じ値で変更したので値自体は変わらない。するとUserChildComponentのログが表示されなかったので、UserChildComponentのChangeDetectionが走ってないことが確認できる。
このことからプリミティブな値は変更が無ければChangeDetectionが走らないことがわかる。
今回はChangeDetectionの効果を可視化してみた。 ChangeDetectionStrategy.OnPushを設定することでChangeDetectionの無駄を省くだけでなく、オブジェクトをImmutableを半強制的に扱わせられることもわかった。(半強制的なのはImmutableでなくても自分でChangeDetectionするメソッドを呼べるため。) ダッシュボード画面のように複数のオブジェクトを表示するようなときにこのChangeDetectionStrategy.OnPushを設定すると幸せになるかもしれない。 参考 Angular2のChange Detectionについて Angular2はいかにしてオブジェクトの変更を監視しているのか 日本語訳:Angular 2 Change Detection Explained angular-change-detection-example |
今日新闻 |
点击排行 |
|
推荐新闻 |
图片新闻 |
|
专题文章 |
CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭 |