DEV Community

JiaLiPassion for Angular Japan User Group

Posted on

4 2

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を提出ください。

以上です。

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

Do your career a favor. Join DEV. (The website you're on right now)

It takes one minute and it's free.

Get started

Top comments (0)

AWS Security LIVE!

Tune in for AWS Security LIVE!

Join AWS Security LIVE! for expert insights and actionable tips to protect your organization and keep security teams prepared.

Learn More

👋 Kindness is contagious

Explore a sea of insights with this enlightening post, highly esteemed within the nurturing DEV Community. Coders of all stripes are invited to participate and contribute to our shared knowledge.

Expressing gratitude with a simple "thank you" can make a big impact. Leave your thanks in the comments!

On DEV, exchanging ideas smooths our way and strengthens our community bonds. Found this useful? A quick note of thanks to the author can mean a lot.

Okay