2016-12-27 12 views
3

モーダルを複数回開いたときにパフォーマンス上の問題に直面していましたが、ダイアログサービスが新しいモーダルを作成するようになるたびに、スコープの数が劇的に増加します。次のように

はDialogServiceは次のとおりです。

.factory("DialogService", function($q, $compile){ 
     return { 
      toast:function(text){ 
       Dialog.toast(text); 
      }, 
      alert:function(text){ 
       var deferred = $q.defer(); 
       var d = Dialog.alert(text); 
       d.bind("hide", function(){ 
        deferred.resolve(); 
       }); 
       return deferred.promise; 
      }, 
      showModal:function(options){ 
       var dialog = new Dialog(options); 
       dialog.show(function(){ 
        var self = this; 
        if ("scope" in options) $compile(self.contentLayer)(options.scope); 

        options.scope.dismiss = function(){ 
         dialog.hide(); 
        } 
       }); 
       if ("hide" in options){ 
        dialog.bind("hide", options.hide); 
       } 
      },... 

問題 - 私の対面が新しいモーダルが作成されるたびに、それは私がディレクティブを使用して新しいウォッチャーとスコープをpolutesということです。

カスタムディレクティブでノードが破棄されたときにウォッチャーを削除するオブザーバーを追加することで問題のほとんどを修正しましたが、ng-repeat、ng-ifなど... showModalが毎回ウォッチャーを追加し続けますと呼ばれる。

今、私はどのようなアプローチを試すべきかもわかりません。

今、私はダイアログで作成されたウォッチャーを削除しようとしていますが、成功しなかったので、助けていただければ幸いです。

+0

偽のスコープオブジェクトを作成し、それをオプションに渡すとどうなりますか(ダイアログにスコープにプロパティが必要な場合)または、単にスコープオブジェクトを渡さないとしたら? –

+0

angleは、スコープが破棄されたときにスコープに登録されているウォッチャーを自動的に削除します。各モーダルに対して同じスコープを何度も何度も繰り返し使用していますか、手動でDOM要素を追加したり削除したりしていますか? – TheSharpieOne

+0

ガードコレクタがスコープオブジェクトを破棄するときに、ビルトインディレクティブによって追加されたウォッチャーがスコープとともに角をなして削除されます。 –

答えて

0

は私にいくつかの時間がかかりましたが、最終的に私は希望の動作

ファーストを達成することができました、代わりに質問に示すように、ダイアログサービスに直接スコープを渡すので、子スコープを作成するために、より良いit'sオプションで渡されたスコープから

このように、$ compileがモーダルを構築するために呼び出されるたびに、モーダルが閉じられたときに新しく作成されたスコープを破壊するのは簡単です。

サービスの結果のコードは次のようになります。この時点で

angular.module("app", []) 
    .factory("DialogService", function($q, $compile){ 
     return { 
      toast:function(text){ 
       Dialog.toast(text); 
      }, 
      alert:function(text){ 
       var deferred = $q.defer(); 
       var d = Dialog.alert(text); 
       d.bind("hide", function(){ 
        deferred.resolve(); 
       }); 
       return deferred.promise; 
      }, 
      showModal:function(options){ 
       var childScope; 
       var dialog = new Dialog(options); 
       dialog.show(function(){ 
        var self = this;  
        if ("scope" in options){ 
         var childScope = options.scope.$new(); 
         $compile(self.contentLayer)(childScope); 

         options.scope.dismiss = function(){ 
          dialog.hide(); 
         } 

         dialog.bind("hide", function(){ 
          childScope.$destroy(); 
         }); 
        } 
       }); 
       if ("hide" in options){ 
        dialog.bind("hide", options.hide); 
       } 
      }, 
      confirm:function(text){ 
       var deferred = $q.defer(); 
       Dialog.confirm(text, function(){ 
        deferred.resolve(); 
       }, function(){ 
        deferred.reject(); 
       }); 
       return deferred.promise; 
      } 
     } 
    }) 
; 

エクストラ

、私は問題を解決思ったが、コンソールログを私はそれがサイクルを消化見ることができました私は新しいダイアログを開くたびにますます稼働していますが、今回は時計が一定のままです。

私はカスタムディレクティブがたくさんあるということが起こっていました。上記のようなシナリオでは、パフォーマンスの問題を回避するために、すべてのdirective'sリンク機能の末尾に以下の行を追加することについて非常に慎重に - 私:

var watchers = [ 
    $scope.$watch(...), 
    $scope.$watch(...), 
    ... 
]; 
... 
var observer = new MutationObserver(function(mutations) { 
    if (!document.body.contains($element[0])){ 
     observer.disconnect(); 
     dropdown.remove(); 
     for (var i = 0; i < watchers.length; i++){ 
      watchers[i](); 
     } 
     $scope.$destroy(); 
     return; 
    } 
}); 
var config = { childList: true, subtree: false /*attributes: true, characterData: true*/ }; 
observer.observe(document.querySelector('body'), config); 

は右、正常に見えますか?うーん...ほとんどの時間の作品が、私はディレクティブ内でこのような何かを持っている場合(それはそうだった):

var clickHandler = function(event){ 
    var isChild = $($element).has(event.target).length > 0 || $(dropdown).has(event.target).length > 0; 
    var isSelf = $element[0] == event.target || dropdown == event.target; 

    $scope.$apply(function(){ 
     if (!isChild && !isSelf) { 
      $scope.mdSelectCtrl.dismiss(); 
     } 
    }); 
} 

$document.bind('click', clickHandler); 

それは、コンパイルクリックイベントの原因を、すべての$上のクリックイベントを追加しました別のダイジェストサイクル(たとえスコープが破壊されたとしても、この時点では深く掘り下げたいとは思わなかった)。モーダルコンテンツで同じディレクティブを10〜15回簡単に使うことができるということを考慮すると、$ compileを呼び出すたびに、クリックごとに多くのダイジェストサイクルが実行され、パフォーマンスが低下します。

これに対する解決策は簡単です:ディレクティブのスコープが破棄されると、DOMのイベントリスナーを削除します。

var observer = new MutationObserver(function(mutations) { 
    if (!document.body.contains($element[0])){ 
     observer.disconnect(); 
     dropdown.remove(); 
     for (var i = 0; i < watchers.length; i++){ 
      watchers[i](); 
     } 
     $scope.$destroy(); 
     $document.unbind('click', clickHandler); 
     return; 
    } 
}); 

ダイアログサービスを変更した後、私は多分MutationObserverであることを実感ノードがまだ存在するかどうかを追跡する必要はなく、代わりに使用できます。

$scope.$on("destroy") 

ウナギは今日のためにそれをテストするためのコードを変更するのが好きです。

関連する問題