概要
Angular, RxJSを使う人であれば**「必ずunsubscribeする」**は何度も聞いたことがあると思います。以前書いた記事でも触れたように、この理由は「コンポーネントが破棄されてもSubscriptionだけが残り続けてしまうため」です。私も頭ではわかっていつつも実際にこれでハマった例をみたことがなかったのですが、ちょうど少し前にそういうケースに出くわしたのでデモを作ってみました。まだ使い始めでピンと来ない人などの理解の手助けになれば嬉しいです。
デモ
肝心のデモはこちらです。
簡単にシステムを説明します。左のボタンでどのおばけを出すか切り替えることができます。activeになったおばけは「おばけを出す」ボタンのクリックイベントをsubscribeするようになります。一度activeを切り替えるたびに、subscribeしていたコンポーネントのインスタンスは破棄されます。
このおばけのなかに、unsubscribeを忘れているおばけがいるのでデモを操作してどれか当ててみてください 簡単なので書くまでもないかもしれませんが、次の解説欄に答えを載せます。
デモの解説
前述の通り、activeを切り替えるたびに、subscribeしていたコンポーネントのインスタンスは破棄されます。ですが、ngOnDestroy
で正しくunsubscribeされていない場合はコンポーネントが破棄されてもsubscribeしているsubscriptionは破棄されません。そのため、別のおばけにactiveを切り替えても、「おばけを送る」ボタンを押した時に前のおばけも一緒に出てくるようになるのです。参考までに、今回のコードはこちらです。
それでは、デモの動きをまとめて答えを見てみましょう。
- 1つめのを選ぶ
- 2つめのを選ぶ
- 「おばけを送る」
- 1つめと2つめのが出る
:よって1つめのおばけはunsubscribeしわすれています。 - 3つめのを選ぶ
- 「おばけを送る」
- 1つめと2つめと3つめのが出る
:よって2つめのおばけはunsubscribeしわすれています。 - 再度1つ目のおばけを選ぶ
- 1つめのおばけx2、2つめのおばけが出ます
:よって3つめのおばけはunsubscribeされています。
何が怖いのか
適当にactiveを切り替えてボタンを押すとわかると思いますが、後始末されてない場合、一度のイベント発火でのsubscribe処理がactiveを切り替えるたびにわさわさと増えていきます。 これがもし、おばけを出すのではなくバックエンドからデータを取得する処理だったらどうでしょうか。操作をするたびにどんどんリクエストが増え、画面が重くなっていきます。恐ろしいですね…
おまけ:こういう時は後始末忘れかも
上記で述べたとおり、1つのイベントに対して1回しか走るはずのない処理(上記例で言えば、バックエンドへのリクエスト)がたくさん同時に起きている場合、後始末忘れが予測されます。
そのほかに、**「subscribe処理が思うような挙動をしない」**場合もこのケースがありえます。すでに述べたように、subscriptionは残っていてもコンポーネント自体は破棄されているので、例えばsubscribeの中でコンポーネントの変数を更新していても更新されないのです。console.log
で確認して絶対にここにイベントは届いているのに、ビューに反映されない!ということがあれば、これも後始末忘れの可能性があります。
まとめ
特にエラーの出るような種類のものではないため、みんなで気をつけていくのが大事ですね