先日の ng-japan OnAir を視聴していて知ったこと。サービスに ngOnDestroy が書けるとのこと。知らなかった…!
この記事のコードの前提条件
- Angular 15
サービス
コンポーネントとサービスのライフタイムが一致する場合
コンポーネントメタデータの providers でサービスを指定する。このようにするとエレメントインジェクターでサービスのインスタンスが生成され、コンポーネントとサービスのライフタイムが一致する。
コンポーネント破棄のタイミングでサービス内の ngOnDestroy が呼ばれる。

コンポーネントよりサービスのほうが長く生存する場合
コンポーネントメタデータの providers でサービスを指定しない。このようにするとルートインジェクターでサービスのインスタンスが生成され、コンポーネントよりサービスほうが長く生存する。(モジュールインジェクターを使っても同じ)
コンポーネント破棄のタイミングでサービス内の ngOnDestroy は呼ばれない。

検証してみる
ルーティングを宣言して、ページ移動によりコンポーネントが生成・破棄されるようにした。
サービスの ngOnDestroy が呼ばれたかコンソール出力で判定する。

home → foo → home とリンクを辿る。 FooComponent(エレメントでサービス注入)が破棄されるタイミングでサービスの ngOnDestroy が呼ばれる。

home → bar → home とリンクを辿る。BarComponent(ルートでサービス注入)が破棄されるタイミングでサービスはまだ生存しているため ngOnDestroy は呼ばれない。

検証したコードは以下のURLで公開。
https://codesandbox.io/s/happy-heisenberg-n6018
ユースケース
サービス内で Observable を購読したり、setInterval で定期処理を実行しているようなケースで役立つ。
コンポーネントの ngOnDestroy で呼び出していた終了処理がサービスの「自分自身が破棄されたタイミング」という関心事になり、終了処理の呼び忘れなどが防げる。利用者であるコンポーネントはインジェクターを変えることで終了処理のタイミングを指示できるようになる。

