21

バックボーンビューがrender()メソッド内に新しいビューを作成する場合、これらのビューはデータメンバーとして維持する必要がありますか?一般的なレンダリング方法は次のようになります。

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

この種のレンダリングメソッドのチェーンは、ネストされたビューが実際に作成されるだけであることを意味します。これにより、任意のレンダリングメソッドをチェーンして、適切に構築された要素を返すことができます。ビューはガベージコレクションのために残されていると思いますか?

ネストされたビューを変更する場合...おそらく大幅に作成する必要がありますか、それともデータメンバー参照を介して変更する必要がありますか?

私が抱えている問題は、ネストされたビューが、独自のネストされたビュー、および場合によっては親のビューを変更する必要があるイベントを受け取ることです。

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

現時点では、フレームワークのようなものではありません。フレームワークのような方法でこの問題を解決するのに役立つリソースを誰かが持っていますか?

4

1 に答える 1

44

(警告:私の答えはtl; dr論文になりました)

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

学習バックボーンの大きな課題は、それが非常に非ピニオンであり、非常に多くの異なる方法で使用できる(そして使用されている)ため、開始時に「正しい」または少なくとも良い方法で何かを行う方法を理解するのが難しいことですアウト。バックボーンを使用する本当の方法は1つだけではありませんが、その柔軟性により、ほとんどすべてのアプリにとって素晴らしい構造になっています。うまくいけば、いくつかのガイダンスを提供するのに役立ちます。(おそらくここのすべての文に「IMO」を付けることができます)。

まず、バックボーンビューについての私の理解

バックボーンアプリには、ビューを使用するための便利な方法がたくさんあります。私は通常、アプリでいくつかの重複するタイプのビューを確認します。

私は通常、1つ以上の「ルートレベル」のビューを持っています。ルートレベルのビューは、多くの場合、ページの特定の部分を処理する子ビューへの参照を初期化、レンダリング、および保持する場所です。ルートelレベルのビューは、多くの場合、「ボディ」またはボディ内の別の高レベル要素です。場合によっては、ルートレベルのビューには、監視および/またはレンダリングするための独自のHTMLがあります。また、ルートレベルのビューにはまったく存在せずel、子ビューを管理するだけの場合もあります。グローバルな「app」名前空間オブジェクト内の各ルートレベルのビュー(多くの場合、1つだけ)への参照を保持します。

「ルートレベル」ビューに加えて、通常は「子ビュー」があります。子ビューは、ルートレベルのビューまたは別の子ビューである「親」ビューによって初期化およびレンダリングされます。親ビューは、アプリの必要に応じて、子の初期化、レンダリング、非表示、表示、および/または破棄を担当します。親ビューが子ビューの可変数のインスタンスを追跡する場合があります(たとえば、PlaylistViewにはN個のSongViewがあります)。多くの場合、親は子への参照を維持しますが、それが不要な場合もあります(これについては以下で詳しく説明します)。

el'root-level / parent / child'パラダイムに加えて、ビューは次の2つのカテゴリのいずれかに当てはまることがよくあります。その中の変化; (2)さまざまなイベントに基づいて出入りする動的。通常、私のルートレベルのビューは常に静的です。また、通常、既存のDOM要素(「body」や「#my-div」など)にも対応します。子ビューは動的であることがよくありますが、静的な場合もあります。(ヒント:静的ビューを宣言するときのようにel: '#element-id'、既存のDOM要素を使用するために使用しelます。動的ビューは通常、既存のDOM要素を指定しません。動的ビューが生成する要素elを使用tagName idおよびclassName記述します。)

ビューには基本的に3つの機能があります。(1)親から指示されたとき、またはイベントに応答して(または、ルートレベルのビューの場合は、ルーターまたは「メイン」関数によって初期化されたときに、自分自身と子をレンダリングします。など)、(2)モデルまたはコレクションを更新するかカスタムバックボーンイベントをトリガーすることにより、 el(子ビュー内ではなく)DOM要素からのUIイベントに応答しel、(3)バックボーン(モデル、コレクションなど)el内で何かをレンダリングまたは変更する必要があるイベント(ただし、子ビューのel内ではありません)。1つの便利なトリックは、子ビューがthis.trigger('customEvent')、親ビューが監視できるイベントを自分自身でトリガーできることです() (childView.on('customEvent', this.handler, this))。

バックボーンビューパターンに関するその他の興味深い視点については、 thisthisを参照してください。

今その文脈で、質問に移ります

1)ガベージコレクション、スコープ、およびメモリリークの恐れ

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

より大きな懸念はゾンビの見解です。ビューをDOMから削除し、アプリのある時点で基本的に破棄する場合は、ビューが完全に削除されるか、親ビューがビューへの参照を保持して削除する必要があることを確認してください。また、すでに作成されていて適切に削除されていないビューを再作成して置き換えないでください。削除は、ビューで.remove()を呼び出すことと、を使用して以前にバインドされた外部バックボーンイベントのバインドを解除することによって実行されon(...) ますoff(...)。Backboneの最近のバージョン(1.0以降)では、Viewプロトタイプに「listenTo」メソッドと「stopListening」メソッドを追加することで、この問題をより簡単に解決できます。DOMとの間でビューを動的に追加する場合は、オン/オフの代わりにこれらのメソッドを理解して使用してください。 ヒント:このようなハッキーなjqueryの「削除」イベントを設定すると、ビューがDOMから削除されたときに、ビューが自律的に削除およびクリーンアップできるようにelなります(アプリフローにイベントがない場合)同じ目的を果たすことができます)。

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

場合によります。親の見解が限られた目的で子の見解を認識していることは、MVCの黄金の原則に違反しているとは思いません。場合によっては、特定の子ビューインスタンスへのメンバー参照を持つ親が、必要に応じて子ビューを管理するための優れた方法です。私が示したように、親ビューは、子ビューのレンダリング、再レンダリング、非表示、または削除を要求するイベントに応答する場合があります。子のビューが自分でトリガーするイベントを聞きたい場合があります。ただし、親は、子のビューの内部にあまり関与するべきではありませんel

とはいえ、これらのタイプの参照を使いすぎないでください。多くの場合、子は自分で面倒を見ることができるため、子ビューへの参照を使用する必要はありません。前述したように、ビューは、レンダリングされると、A)el内のUIイベント(通常は子ビューのel内ではない)を監視し、モデルまたはコレクションを更新するか、これらのUIイベントに応答してイベントをトリガーするか、B)監視する必要があります。他のバックボーンオブジェクト(通常はモデル、コレクション、または他のビュー)からのイベントであり、それに応じてアクションを実行します(たとえば、独自のUI要素を更新します)。多くの場合、ビューはそれ自体を処理し、それ自体を削除することさえできます。別のビューまたは他のバックボーンオブジェクトがビューで発生するUIイベントを気にする場合は、モデルを更新するか、ビューでイベントをトリガーして、それらを監視させます。同じく、ビューの外側にあるものでビューのレンダリングを更新する必要がある場合は、モデルの変更をリッスンするか、対応するカスタムイベントを待ちます。一般原則として、親が理にかなっているときに子供を気にすることを除いて、見解はお互いに幸福に気づいてはいけません。

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

いいえ、ありません。親が観察しているモデルを変更するか、イベントをトリガーすることによっては達成できなかった、親への参照を通じて何かを達成する必要がある単一のシナリオを考えることはできません(たとえば、カスタムイベントの「ねえ、Xが起こった」)子ビュー自体または別のバックボーンの「イベント」ベースのオブジェクト。バックボーンでは、モデルを使用してデータと状態の両方を表します。したがって、アプリケーションの状態を変更するビューで何かが発生した場合は、モデルの対応する状態属性を変更し、他のビュー(親を含む)が気になっている場合は自動「変更」イベントをリッスンします。また、グローバルな「ベント」バスのようなオブジェクト(Backbone.Eventsを拡張する基本的なJavaScriptオブジェクト)を使用して、アプリ全体でイベントをトリガーおよびリッスンします。また、ビュー自体でイベントをトリガーして、親オブジェクトに何かが発生したことを通知することもあります。アーキテクチャを可能な限り解きほぐしながら、機能するものは何でも。

4)私は本当にトップがどこにでもリスナーを投げ始めたくありません。

バックボーンの良い点の1つは、そうする必要がないことですが、オブザーバーパターン(つまり、イベントとリスナー)と緩い結合がバックボーンのMVCのフレーバーの中心にあることを理解してください(すべてのバックボーンクラスがイベントを拡張することに注意してください) ?)、そしてほとんどの人はそれに応じてそれを使用します。

参照?

すでにかなり高度なレベルになっていると感じない限り、 PeepCodeチュートリアルを強くお勧めします。1個あたり12ドルですが、最初の1つから始める必要があります。そうしないと、2番目と3番目はあまり役に立ちません。

また、ここに素晴らしい概要があります

終わり

于 2012-06-08T01:22:50.380 に答える