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

以上です。

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

Image of Docusign

Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs