2016-10-04 9 views
8

javascriptを使用して角度コンポーネントを動的に作成し、新しく作成したスコープで$compileを使用して角をコンパイルします。その後、私がそのコンポーネントのために使用しなくなったら、コンポーネントと新しいスコープを破壊したい。

新しいスコープを破棄しても、使用されるすべてのメモリが解放されないという事実を除いて、すべてが期待通りに機能します。ここで

は、そのコードの簡易版の一部です:このコードの

app.controller("mainCtrl", ["$scope", "$compile", function($scope, $compile) { 
    var childScope; 

    //call this every time the button is clicked 
    this.createDirective = function() { 
     //dynamically create a new instance of the custom directive 
     var customDirective = document.createElement("custom-directive"); 

     //if another child scope exists, destroy it 
     if (childScope) { 
      childScope.$destroy(); 
      childScope = undefined; 
     } 

     //create a new child scope 
     childScope = $scope.$new(); 

     //compile the custom directive 
     $compile(customDirective)(childScope); 
    }; 

}]); 

全作業の例では、すべてこのコードは、新しいコンポーネント]ボタンがクリックされるたびに作成されないhere

ですすでに存在するコンポーネントはすべて破棄してください。 コンパイルしたコンポーネントを実際にページに追加しているわけではないことに注意してください。なぜなら、使用しているかどうかにかかわらず、リークはまだそこに残っていることに気付いたからです。 ( - >レコード割り当てタイムライン - プロファイル>スタート)Chromeの開発ツールを使用して

私はボタン を数回クリックした後、次のメモリ使用量を参照してください。

Memory consumption

任意のメモリを占有することは明らかですスコープの$destroy関数が呼び出されていても、customDirectiveは実際には解放されません。

新しい範囲を作成せずに$compileを正常に使用しましたが、このシナリオでは何か不足しているようです。新しいスコープへの参照がないことを確認するために何か他のことをしなければならないのでしょうか?

app.controller("mainCtrl", ["$scope", "$compile", function($scope, $compile) { 
    var childScope; 

    //call this every time the button is clicked 
    this.createDirective = function() { 
     //dynamically create a new instance of the custom directive 
     var customDirective = document.createElement("custom-directive"); 

     //if another child scope exists, destroy it 
     if (childScope) { 
      childScope.$destroy(); 
      childScope = undefined; 
     } 

     //create a new child scope 
     childScope = $scope.$new(); 

     //compile the custom directive 
     var compiledElement = $compile(customDirective)(childScope); 

     //FIX: remove the angular element 
     childScope.$on("$destroy", function() { 
      compiledElement.remove(); 
     }); 
    }; 
}]); 

Fixed fiddle

答えて

2

私はこれを解決見つけたと思う:https://jsfiddle.net/yqw1dk0w/8/

app.directive('customDirective', function(){ 
    return { 
    template: '<div ng-controller="customDirectiveCtrl"></div>', 
    link: function(scope, element) { 
     scope.$on('$destroy', function() { 
     element.remove(); 
     }); 
    } 
    }; 
}); 

を、私はまだこの作品理由について少しあいまいだけど、ディレクティブは、角度コンパイルのドキュメントでは、をコンパイルしているどのようにこのセクション、手がかりを提供しています。https://docs.angularjs.org/guide/compiler

$前のステップからの結合 リンク機能を呼び出すことにより、スコープとのリンクテンプレートをコンパイルします。これは、順番に、個々のディレクティブの リンク関数を呼び出します要素の登録リスナー と各 ディレクティブが行うように設定されているとして$を設定すると、スコープでwatchs。\

これの結果はスコープとDOMの間のライブバインディング。ですから、この点では、コンパイルされたスコープのモデルの変更がDOMに反映されます。

範囲を破棄すると、これらの要素リスナは削除されません。 destroy directive/child scope on scope destroy

+0

これは実際にはバイブルの例を修正するので、非常に有望なように見えます。私は私のアプリケーションにそれを適用し、それが同様に動作するかどうかを確認します – kapoiosKapou

+1

はい!これは私のより複雑なアプリケーションのためにも動作します.. しかし、私はまだ、なぜこの作品が正しいのか理解していません。私はDOMに追加していないので、なぜそれを削除する必要がありますか? また、コンパイルした要素をDOMに追加して削除しても、メモリはまだ漏れていました。 $ compileはこれを他の場所にも追加していますか?多分キャッシュのように..? – kapoiosKapou

1

それが開始されます:JoelCDoyleにより、下記の回答に基づいて

編集

は、ここでは(私は私が作成したスコープにに破壊する機能を追加)修正です配列をスコープに配置して割り当てを解除すると割り当てを解除する

$scope.array.length = 0; 

をdestcructorに渡します。しかし...知っておきたい。私は密接にメモリ消費を監視する必要があります。スコープが保持されているようだ。私は内部変数の割り当てを解除するだけです。

+0

'this.array'は破壊リスナーの内部で定義されていません(' this'の代わりに 'var'を使って配列を設定します)が、メソッドは健全です。ガベージコレクションはメモリを再利用します。ニース! –

+0

ah ... true、割り当てを解除できるように範囲に割り当てました。編集中... –

+0

これは症状の治療だけであり、実際には問題を解決していません。 その配列は、使用しているすべての変数を手動で削除できない、より複雑なコンポーネントによって使用されるメモリをシミュレートするためにのみ割り当てられます。 – kapoiosKapou

関連する問題