DEV Community

JiaLiPassion for Angular Japan User Group

Posted on

Event Coalescing to improve performance

Event Bubbling の性能の問題

下記のAngularアプリケーションでのHTMLテンプレートコードを見ましょう。

<div (click)="doSomething()"> <button (click)="doAnotherThing()">Button</button> </div> 

Event Bubbling のため、DivのなかのButtonをクリックしたら、両方のEvent ListenerがTriggerされます。この2つのEvent Listenerが全部Change Detectionを実行します。実際はこのようなケースでChange Detectionを一回だけ実行したいです。特にこのようなケースがAngular MaterialとかUI ライブラリで結構普通のケースですので、性能改善したいです。

実行順番

まず上記のケースでEvent ListenerとChange Detectionの実行順番を見ましょう。

export class AppComponent { doSomething() { // event listener for parent div console.log('event listener for parent div'); } doAnotherThing() { // event listener for inner button console.log('event listener for inner button'); } } 

そして、Zone.jsがEvent ListenerをMonkey patchされましたので、下記のような感じのコードになりました。

function eventHandler(...) { try { realHandler(...); // doSomething あるいはdoAnotherThingのDelegate } finally { applicationRef.tick(); } } 

そしたら、Buttonをクリックするとき、実行の順番が下記のようになりました。

event listener for inner button applicationRef.tick event listener for parent div applicationRef.tick 

実際ほしいのは

event listener for inner button event listener for parent div applicationRef.tick 

です。

解決方法

Change Detectionを同期ではなく、非同期で実行することです。

isChangeDetectionScheduled = false; function eventHandler(...) { try { realHandler(...); // doSomething あるいはdoAnotherThingのDelegate } finally { if (isChangeDetectionScheduled) { return; } isChangeDetectionScheduled = true; requestAnimationFrame(() => { isChangeDetectionScheduled = false; applicationRef.tick(); }); } } 

のような感じのコードでChange DetectionをrequestAnimationFrameのSchedulerで実行させ、そしてもしScheduleされたTaskがあったら、スキップして、なかったら、Scheduleするということです。

設定方法

bootstrapModuleのとき、かきのOptionを設定することができます。

platformBrowserDynamic().bootstrapModule(AppModule, {ngZoneEventCoalescing: true}) 

副作用

このオプションをTrueにしたら、もともと同期のChange Detectionが非同期になりました、普通のアプリケーションには影響がないですが、Google 内部でのEdge Caseで同期のChange Detectionが求めるテストケースがあるらしくて、それ以外が特に既存のアプリケーションには影響ないはずです。
この機能がすでに最新バージョンで使えますので、なにか問題が発見されたら、ぜひAngular RepoにIssueを提出ください。

以上です。

どうもありがとうございました!

Top comments (0)