2012-04-09 5 views
20

バックボーンビューでrender()メソッド内に新しいビューが作成される場合、これらのビューはデータメンバとして維持されるべきですか?典型的なレンダリング方法は次のようになります。Backbone.js - ネストされたビューは相互参照を維持する必要がありますか?

render: function() { 
    var myView = new MyView({ model: values }); 
    $('div#value', this.el).append(myView.render().el); 
} 

の方法をレンダリング連鎖するこの種のは、それがあまりにもチェーンが任意のメソッドをレンダリングし、うまく構築要素を返すことができるように、ネストされたビューは、実際にのみ作成されることを意味します。私は仮定ガベージコレクションのためのビューは残っている?

ネストされたビューを変更する場合は、おそらく大きく、作成する必要がありますか、データメンバ参照で変更する必要がありますか?

私が抱えている問題は、ネストされたビューが、自分自身のネストされたビューを変更する必要があるイベントを受け取ることです。

私は本当にどこでも周りのリスナーを投げてトップスタートを望んでいません。また、親ビューへの参照を渡し、子ビューからrender()を呼び出すと、元の子ビューがその親への参照を保持している間に、親が新しい子ビューを作成するのでメモリリークが発生します。

現時点ではそれほどフレームワーク的ではありません。誰も私がフレームワークのような方法でこの問題を解決するのに役立つリソースがありますか?

+1

クロージャと何のライブ参照やバインディングを持っていないオブジェクトは、少なくとも、彼らは既存の何かへの参照を持っているという理由だけでメモリリークが発生することはありません私は認識しているガベージコレクションスキームではありません...確かにいくつかのガベージコレクションエンジンは循環参照(手動で参照を処理することなく)ではうまく動作しませんが、JavaScriptはMark-and-Sweepを使用し、 。 AFAIKの最悪の問題は、DOMとjavascriptの「世界」との間のクロスリファレンスによるものです。 – JayC

答えて

44

(警告:私の答えはTLになった; DRの論文)

私は早い段階でこれらの同じ質問のいくつかを持っていた、といくつかのかなり複雑なアプリケーションを構築するために、宿題をやってきたので、私が提供しています私の視点。

バックボーンを学ぶことの大きな課題は、それほどユニークではなく、さまざまな方法で使用することができるということです。これは、「正しい」、あるいは少なくとも良い方法で行うことが難しいことです。あなたは出発しています。バックボーンを使用する真の方法は1つだけではありませんが、その柔軟性はほとんどのアプリにとって素晴らしい構造になります。 (私はおそらく、ここにあるすべての文に「IMO」を付けることができます)。

まず、バックボーンの私の理解は、バックボーンのアプリで

を見て、ビューを使用するための便利な方法がたくさんあります。私は通常、私のアプリケーションでいくつかの重複するビューの種類を参照してください:

私は通常、 "ルートレベル"のビューを1つ以上持っています。ルートレベルのビューは、多くの場合、ページの特定の部分を処理する子ビューへの参照を初期化、レンダリング、および保持する場所です。ルートレベルのビューのelは、本体内の「本体」または別の高位要素です。場合によっては、ルートレベルのビューに独自のHTMLを使用して監視および/またはレンダリングすることができます。他のものでは、ルートレベルのビューにはelがまったくなく、子ビューのみが管理されます。グローバルな「app」名前空間オブジェクトには、各ルートレベルビュー(しばしば1つしかない)への参照を保持します。

"ルートレベル"ビューに加えて、通常は "子ビュー"があります。子ビューは、「親」ビュー(ルートレベルビューまたは別の子ビュー)によって初期化され、レンダリングされます。親ビューは、アプリケーションの必要に応じて、初期化、レンダリング、隠蔽、表示、および/または破棄を担当します。親ビューは、子ビューの可変数のインスタンスを追跡することがある(例えば、PlayListViewはN個のSongViewを有する)。多くの場合、両親は子供への言及を保持していますが、時にはそれは不要です(これについては後述)。

「ルートレベル/親/子」のパラダイムに加えて、ビューは2つのカテゴリの1つに収まります。(1)静的:ビューが初期化されるとビューとそのelスティックたとえ内部のものが変更されたとしても。 (2)さまざまな出来事に基づいて行き来するダイナミック。通常、私のルートレベルのビューは常に静的です。これらは、通常、 'body'や '#my-div'などの既存のDOM要素にも対応しています。子ビューは動的であることが多いが、静的でもよい。 (ヒント:静的ビューを宣言するときelとして、既存のDOM要素を使用するel: '#element-id'を使用して、動的ビューは、通常、既存のelを指定していない。彼らは、動的なビューが生成されるという要素を記述するためにtagNameidclassNameを使用しています。。)

ビューには基本的に次の3つの機能があります。(1)親やイベントに応じて(ルーターレベルのビューの場合は、ルーターやメイン(2)モデルやコレクションを更新したり、カスタムBackboneイベントをトリガしたりして、el内のDOM要素のUIイベントに応答します(子ビューのelには含まれません)。(3)バックボーン(modイベントのトリガーとなることがあります(this.trigger('customEvent'))。その親(親イベント)は、ビューは(childView.on('customEvent', this.handler, this))を観察することができます。

バックボーンビューパターンについてのさらに興味深い見通しについては、thisおよびthisを参照してください。質問

1の上にその文脈で今

、)ガベージコレクション、範囲、およびメモリリークの

の恐怖あなたは親の(レンダリングにおける局所的なVARとして、子ビューをインスタンス化した場合それをレンダリングしてから関数がスコープ外になると、ガベージコレクションの恐れやビューが必要な処理を実行できなくなることが理解できます。ガベージコレクター、ちょうどゾンビを恐れる必要はありません。 UIイベントハンドラが「イベント」宣言で宣言されているか、他のBackboneオブジェクトのイベントまたは他のDOMベースのイベントリスナにバインドされているかにかかわらず、ビューにはイベントハンドラがありますが、もはやそれを参照している - それはまだメモリに存在し、イベントに応答します。一方、ビューにイベントハンドラがない場合、唯一の仕事は要素をレンダリングすることです。そのため、レンダリングされたjavascriptオブジェクトがスティックされると誰が気になりますか?それはおそらくガベージコレクションされます。一般的なjsガベージコレクションと、それがBackbone.jsとどのように関係しているかについては、thisを参照してください。

大きな問題はZombie viewsです。ビューがDOMから削除され、アプリのある時点で削除される場合は、それらのビューが完全に削除されているか、親ビューがそのビューを参照して削除する必要があります。また、すでに作成され、適切に削除されていないビューを再作成して置換しないでください。削除は、ビュー上で.remove()を呼び出すこと、およびon(...)を使用して以前にバインドした外部バックボーンイベントのバインドを解除して、off(...)を使用して行います。 Backboneの最近のバージョン(1.0+)は、"listenTo" and "stopListening" methodsをViewプロトタイプに追加することで、この問題をより簡単に解決しました。 DOMとの間でビューを動的に追加する場合は、これらのメソッドをオン/オフではなく、理解して使用してください。 ヒント:a hacky jquery "remove" event like this oneを設定すると、elがDOMから削除されたとき(アプリケーションフロー内に同じ目的を果たすイベントがない場合)に、自動的にビューが自動的に削除およびクリーンアップできるようになります。

2)親ビューのデータメンバーとして子ビューを維持する必要がありますか?

によって異なります。限られた目的のために子ビューを認識している親ビューがMVCの何らかの黄金原則に違反するとは思わない。時には、特定の子ビューインスタンスへのメンバ参照を持つ親は、子ビューを必要なときに管理するための優れた方法です。上に示したように、親ビューは、子ビューをレンダリング、再レンダリング、非表示、または削除する必要があるイベントに応答することがあります。時には、子どもの視点が自分自身で引き起こすイベントを聴きたいことがあります。しかし、両親の子供の意見の​​中には何も関わってはいけません。 'el'

しかし、これらの種類の参照を過度に使用しないでください。子供が自分自身を世話することができるので、多くの場合、子ビューへの参照を使用する必要はありません。前述したように、ビューは一度レンダリングされるとA)UI内のUIイベント(通常は子ビューのel内にない)を監視し、モデルやコレクションを更新するか、これらのUIイベントに応答してイベントをトリガーするか、B)他のバックボーン・オブジェクト(典型的にはモデルまたはコレクションまたは他のビュー)からのイベントを受け取り、それに応答してアクション(例えば、自身のUIエレメントを更新する)を行う。多くの場合、ビューはそれ自体を処理し、それ自体を削除することもできます。別のビューまたは他のバックボーンオブジェクトが、あなたのビューで起こっているUIイベントを気にしている場合は、モデルを更新するか、ビュー上のイベントをトリガーして観察させます。同様に、ビュー外のものがビューの更新されたレンダリングを必要とする場合は、モデルへの変更をリッスンするか、対応するカスタムイベントを待機します。一般的な原則として、お互いに幸せに気づかないといけません。

3)子ビューは親ビューへの参照を保持する必要がありますか?

いいえ。私は、親が参照しているモデルを変更するか、イベントをトリガーすることによって達成できない親への参照を通じて何かを達成する必要があるという単一のシナリオを考えることはできません(例えば、カスタムイベント"ちょっと、Xが起こった")、子ビュー自体、または別のバックボーンの "イベント"ベースのオブジェクト。バックボーンでは、モデルを使って自分のデータと自分の状態を表現します。したがって、アプリケーションの状態を変更するビューで何かが発生した場合、モデルの対応する状態属性を変更し、気にしていれば、他のビュー(親を含む)が自動「変更」イベントを聞くようにします。私はまた、アプリ全体のイベントをトリガしてリッスンするためのグローバルな「通気」バスのようなオブジェクト(Backbone.Eventsを拡張する基本的なjavascriptオブジェクト)を使用します。 。どのような作品でも、あなたのアーキテクチャを可能な限りアンバランスに保ちます。

4)私は本当にどこでも周りのリスナーを投げてトップスタートを望んでいません。

まあ、私はすべてのことに気づく(バックボーンについての一つの良い事はあなたがする必要がありますが、Observerパターン(すなわちイベント&リスナー)と疎結合は、MVCのバックボーンの香りの心臓部であることを理解していないということだと思います単一のBackboneクラスはEventsを拡張しています)、ほとんどの人がそれを適切に使用します。

参考資料ですか?

あなたがかなり高度なレベルにいると思わない限り、PeepCode tutorialsを強くお勧めします。 12ドルの1ドルで始まりますが、最初の1つまたは2番目のものから始める必要があります。&はあまり役に立ちません。また、here's a nice overview。(基本的にゴミを収集するのを待っている)どこでも彼らに

エンド

+0

ありがとうございます。それは信じられないほど役に立つものでした。 – user941521

+0

うーん、@ベンR! +1:D –

+1

"あなたのビューにイベントハンドラがある場合は、もう参照がなくてもガベージコレクションは行われません。それはメモリに残っていて、イベントに応答します。単体テストを書くときに覚えておくべきこと! –

関連する問題