https://docs.angularjs.org/guide/directive
このイベントをリッスンすることで、メモリリークを引き起こす可能性があるイベントリスナーを削除できます。スコープおよび要素に登録されたリスナーは破棄されると自動的にクリーンアップされますが、サービスにリスナーを登録した場合、または削除されていないDOMノードにリスナーを登録した場合は自分でクリーンアップする必要があります。あなたはメモリリークを引き起こす危険があります。
ベストプラクティス:指令は自分自身の後で片付けるべきです。ディレクティブが削除されたときにクリーンアップ関数を実行するには、element.on( '$ destroy'、...)またはscope。$ on( '$ destroy'、...)を使用できます。
質問:
ディレクティブの中にelement.on "click", (event) ->
があります。
element.on
へのメモリ参照はありますか?$destroy
が発行したイベントのイベントリスナーを削除するにはハンドラを使うべきだと述べています。 destroy()
がイベントリスナーを削除したという印象を受けましたが、そうではありませんか?まず、2種類の「イベントリスナー」があることを理解することが重要です。
$on
で登録されたスコープイベントリスナー:
$scope.$on('anEvent', function (event, data) {
...
});
on
やbind
などを介して要素に結びつけられたイベントハンドラ:
element.on('click', function (event) {
...
});
$scope.$destroy()
が実行されると、その$スコープに$on
を通して登録されているすべてのリスナーを削除します。
notDOM要素や第2種の添付イベントハンドラを削除します。
つまり、ディレクティブのリンク関数内でexampleから$scope.$destroy()
を手動で呼び出しても、たとえばelement.on
を介してアタッチされたハンドラもDOM要素自体も削除されません。
remove
はjqLiteメソッド(またはjQueryがAngularjSの前にロードされている場合はjQueryメソッド)であり、標準のDOM要素オブジェクトでは使用できないことに注意してください。
element.remove()
が実行されると、その要素とそのすべての子が一緒にDOMから削除され、すべてのイベントハンドラが例えばelement.on
を通じてアタッチされます。
それはnot要素に関連する$スコープを破壊するでしょう。
さらに分かりやすくするために、$destroy
というjQueryイベントもあります。要素を削除するサードパーティのjQueryライブラリを使用している場合、または手動で要素を削除した場合は、その場合にクリーンアップを実行する必要があります。
element.on('$destroy', function () {
scope.$destroy();
});
これは指令がどのように「破壊される」かによって異なります。
ng-view
は現在のビューを変更するため、通常はディレクティブが破壊されます。これが起こると、ng-view
ディレクティブは関連する$スコープを破壊し、その親スコープへのすべての参照を切断し、その要素に対してremove()
を呼び出します。
これは、そのビューがng-view
によって破棄されたときにそのリンク関数にthisを含むディレクティブが含まれている場合です。
scope.$on('anEvent', function () {
...
});
element.on('click', function () {
...
});
両方のイベントリスナーは自動的に削除されます。
ただし、たとえば、一般的なJSメモリリークパターンcircular references
を達成した場合など、これらのリスナー内のコードによってメモリリークが発生する可能性があることに注意することが重要です。
ビューが変更されたためにディレクティブが破壊されるこの通常の場合でも、手動でクリーンアップする必要があるかもしれません。
例えば$rootScope
にリスナーを登録したならば:
var unregisterFn = $rootScope.$on('anEvent', function () {});
scope.$on('$destroy', unregisterFn);
$rootScope
はアプリケーションの有効期間中に破棄されることはないため、これが必要です。
$ scopeが破棄されたときに必要なクリーンアップを自動的に実行しない別のpub/sub実装を使用している場合、またはディレクティブがコールバックをサービスに渡す場合も同様です。
別の状況は$interval
/$timeout
をキャンセルすることです。
var promise = $interval(function () {}, 1000);
scope.$on('$destroy', function () {
$interval.cancel(promise);
});
たとえば現在のビューの外側などでディレクティブがイベントハンドラを要素に関連付ける場合は、それらも手動でクリーンアップする必要があります。
var windowClick = function () {
...
};
angular.element(window).on('click', windowClick);
scope.$on('$destroy', function () {
angular.element(window).off('click', windowClick);
});
ng-view
やng-if
など、Angularによってディレクティブが「破棄」されたときの対処方法の例をいくつか示しました。
DOM要素などのライフサイクルを管理するカスタムディレクティブがある場合は、もちろんもっと複雑になります。