16

jquery-ui Tabsを使用していますが、タブが削除されたときに問題が発生します。タブはコンテンツ div とともに削除されているように見えますが、(タブが削除された後に) Chrome DevTools プロファイルのヒープを見ると、タブの li 要素と div 要素がまだ存在していることがわかりますが、分離されています。 . 時間が経つにつれて、タブの追加/削除が繰り返されると、これらの要素が蓄積されます。たとえば、タブを 10 回追加すると、10 個の切り離された div 要素と 10 個の切り離された li 要素がヒープ スナップショットに表示されます。

切り離された要素を含むヒープ スナップショット

私は次の見解を持っています:

TabLabel = Marionette.ItemView.extend({
    template: "#tab-label",
    tagName: "li",
    events: {
        "click .ui-icon-close": "closeTab"
    },  
    closeTab: function(e) {
        this.$el.contents().remove();
        this.model.collection.remove(this.model);
        $("#main-container").tabs("refresh");
        this.close();
    }   
}); 

TabContainer = Marionette.ItemView.extend({
    template: "#tab-container",
    tagName: "div",
    onBeforeRender: function() {
        this.$el.attr("id", "div-" + this.id);
    },  
    onClose: function() {
        // This removes the region that contains the container
        App.layout.removeRegion(this.containerRegion);
    }   
});

TabLabels = Marionette.CollectionView.extend({
    tagName: "ul"
});

TabContainers = Marionette.CollectionView.extend({
    tagName: "div"
});

ビューは次のようにインスタンス化されます。

tabs = new TabsCollection(); // Create a new collection instance

var tabLabelView = new TabLabels({
    itemView: TabLabel,
    collection: tabs
}); 

var tabContainerView = new TabContainers({
    itemView: TabContainer,
    collection: tabs
}); 

ご覧のとおり、両方のビューが同じコレクションを参照しています。コレクション内の各モデルは、単一のタブを表していると言えます (たまたま、モデルには jquery-ui タブを満たすために必要な情報が含まれています)。ビューは Marionette.Layout を介して領域に表示されます...かなり標準的です。タブを追加するには、タブ コンテナー内のリンクをクリックします。これは、別のモデルをコレクションに追加し、メイン コンテナーで tabs("refresh") を呼び出すだけで、新しいタブが表示されます。タブを削除するには、タブの右上隅にある「X」アイコンをクリックします。

このリークを追跡するために多くの時間を費やしましたが、それが私のコードの問題なのか (おそらくビュー/モデル/などを閉じる方法に問題があるのか​​?)、それともjquery-ui タブ プラグイン。

考え?前もって感謝します!

更新 #1要求に応じて、問題を示すjsfiddleを次に示します。タブを閉じるだけで、切り離された要素が取り残されていることがわかります。

また、スクリーンショット:

ここに画像の説明を入力

更新 #2これは、jquery-ui タブ ウィジェットのリークのようです。jquery-ui Web サイトのウィジェットのデモでも同じ動作が発生します。いくつかのタブを追加してからそれらを閉じましたが、確かに、それらは持続しました:

ここに画像の説明を入力

これは、jQuery UI の最新 (この記事の執筆時点) バージョン (1.10.3) と以前のバージョン (1.10.2) でテストしました。

4

2 に答える 2

4

this.$el.contents().remove()の代わりに使用する理由はありますthis.$el.empty()か?

this.$el.empty()あなたのそのjsFiddleで使用すると、切り離されたNodeListが改善されたようです。

いくつかのメモ メモリ プロファイリング:

  • http://www.youtube.com/watch?v=L3ugr9BJqIsを見る
  • 3 つのスナップショット メソッドを使用します。2 つでは不十分です。どういう意味ですか?
    • フレッシュ、シークレットモード、リフレッシュを開始
    • スナップショットを作成します (スナップショットを作成するたびに GC が強制的に実行されます)
    • 何かをして、スナップショットを撮る (gc)
    • 似たようなことをして、スナップショットを撮ります (gc)
    • スナップショット 2 とスナップショット 1 を比較し、+ でデルタを見つけます
    • スナップショット 3のスナップショット 1 と 2 の間に割り当てられた[概要]と[オブジェクト] を選択します。
    • 2 と 1 を比較して見つけた、あってはならないものを探します。これらはニラです

.prevObjectを呼び出すなどの操作を行うときに現在の jQuery オブジェクトを保存するため、jQuery がリークしているように見えるケースを見つけました.add()。たぶん、.contents()ファンキーな魔法をするためのその呼び出し。

于 2013-09-03T12:53:22.107 に答える
3

したがって、私は最終的にこの問題を(かなり前に)次の2つのことで修正しました。

  1. Bootstrapを支持してjQueryUIを捨てる
  2. closeTab 関数 (元の jsFiddle を参照) を次のように変更します。

    closeTab: function (e) {
        e.stopPropagation();
        e.preventDefault();
        this.model.collection.remove(this.model);
        this.close();
    }
    

そのスニペットでは、stopPropagation と preventDefault が実際に、この要素が DOM で分離されたままになる (そしてその後の追加/削除で蓄積される) のを止めました。要約すると、この問題は、イベント オブジェクトがトリガーされた後に stopPropagation/preventDefault を呼び出さないために発生しました。タブ要素を正しく削除するようにjsFiddleを更新しました。後世のために、結果のスクリーンショットを次に示します。

更新されたjsFiddle

ご覧のとおり、「X」をクリックしてタブ要素を閉じた後、タブ要素はどれも切り離されたままではありません。切り離された要素は、jsFiddle のインターフェースからのものだけです。

于 2013-12-19T15:24:32.473 に答える