1

Backbone-on-railsgemのBackbone.js0.9.2を使用しています。また、古いハッシュURLの代わりに新しい「pushState」を使用しようとしています。

問題

予定を追跡するために、CRUDインターフェースのような標準のRailsを構築しています。メインのindex.jst.ecoページに「新しい」リンクがあります。

<h1>Appointments</h1>
<p><a href="/appointments/new" class="new">New Appointment</a></p>

ページをロードしてその「新しい」リンクをクリックすると、バックボーンがイベントを発生させ、ページ全体をリロードする必要はありません。そのイベントは次のとおりです。

class BackboneOnRails.Views.AppointmentsIndex extends Backbone.View
  template: JST['appointments/index'],
  events: ->
    'click .new': 'newAppointment'

  newAppointment: ->
    Backbone.history.navigate("/appointments/new", {trigger: true})
    return false

  # The rest of the index methods omitted for brevity 

次に、バックボーンルーターを呼び出します。

class BackboneOnRails.Routers.Appointments extends Backbone.Router
  routes:
    '': 'index'
    'appointments': 'index'
    'appointments/new': 'new'

  initialize: ->
    this.appointments = new BackboneOnRails.Collections.Appointments()
    this.appointmentsIndexView = new BackboneOnRails.Views.AppointmentsIndex({collection: this.appointments})
    this.appointmentsIndexView.render()

  index: ->
    $("#container").html(this.appointmentsIndexView.el)
    this.appointments.fetch()

  new: ->
    appointments = new BackboneOnRails.Collections.Appointments()
    view = new BackboneOnRails.Views.AppointmentNew({collection: appointments})
    $("#container").html(view.render().el)

この問題は、ブラウザの戻るボタンを押してから、「新規」リンクをもう一度使用してみると発生します。今回は、ページの完全なリロードを実行します。

ブラウザに戻ったときにjavascriptバインディングはどうなりますか?

アイテムのショーイベントがあり、問題なく行き来できます。両方を比較しましたが、同じ種類の呼び出しのように見えます。

4

1 に答える 1

4

問題は、appointmentsIndexViewインスタンスを再利用しようとしたことにあります。DOMからビューを削除すると、DOMイベントハンドラーが破棄されます。ビューをDOMに再追加しても、ビューelは再接続されません。

問題の概要

initializeルーターのメソッドとメソッドを使用してそのビューを初めてロードするときindexは、IndexViewの新しいインスタンスがあるため、すべて問題ありません。DOMイベントはビューに適切にアタッチされており、生活は良好です。

ルーターのnewルート/メソッドを押すと、画面からインデックスビューを効果的に削除し、新しいビューを追加するように置き換えようとしています。これは、視覚的な観点から、および新しいビューの追加の観点から機能します。

ただし、戻るボタンを押すと、ブラウザタブの同じライブアプリケーションインスタンス内にとどまります。pushstateを有効にして戻るボタンを押すと、アプリ全体をリロードせず、URLを更新して、インデックスのルーターメソッドを起動するようにブラウザに指示します。

この場合、インデックスビューはゼロから再構築されません。同じビューインスタンスを再利用していますが、サーバーからのデータを再ロードしています。ビューとコレクションがまだ接続されているため、データの読み込みは完全に正常に機能します。ただし、DOMイベントのバインディングは、以前に削除され、再度追加されていないため、失敗します。

2つの一般的なソリューション

これには2つの一般的な解決策があり、これらの解決策には多くのバリエーションがあります。

1)ビューインスタンスを再利用しないでください。

これは私の強くお勧めする提案です。ビューインスタンスを再利用しようとしたすべてのインスタンスで、私は一貫して非常に大きな問題に遭遇しました-あなたが抱えている正確な問題を含みます。

代わりに、予定のインデックスを表示する必要があるたびに、新しいビューインスタンスを再作成します。つまり、indexメソッドではなく、ルーターのメソッドで新しいインデックスビューを作成しますinitialize

2)DOMイベントをクリアして再バインドします

何らかの理由で、ビューインスタンスを本当に再利用する必要があると感じた場合(これは決して真実ではないはずです)、TimBranyenがしばらく前にブログに投稿した情報で解決できます。

http://tbranyen.com/post/missing-jquery-events-while-rendering

このアプローチはお勧めしません。ビューインスタンスを再利用することは手に負えない良い考えのように思えるかもしれませんが、アプリに未使用の部分が多すぎることによるメモリ使用量の肥大化など、他の問題への悪い道をたどります。

補足:ゾンビとメモリリーク

いずれの場合も(ビューインスタンスを再利用するか、必要なときに再作成するか)、メモリリークが発生する可能性があります。

ビューを再利用する場合、必要のないときにメモリ内のオブジェクトを明示的に保持します。これは実際には「リーク」ではありませんが、メモリの過度の使用です。オブジェクトが不要な場合は参照を解除し、必要な場合は再作成する必要があります。これにより、メモリ使用量が削減され、アプリのパフォーマンスが向上します。

これがどのように機能するかをカバーするブログ投稿があります:http://lostechies.com/derickbailey/2012/03/19/backbone-js-and-javascript-garbage-collection/

ビューを再利用しない場合、ビューが表示されているDOMから削除された後、モデルとコレクションのイベントバインディングがぶら下がったままになると、真のメモリリークが発生する可能性があります。ビューを再利用しないことにした場合は、 #containerhtmlを置き換えるコードをより堅牢にし、古いビューをクリーンアップする必要があります。

その解決策について詳しく説明しているブログ投稿もあります:http://lostechies.com/derickbailey/2011/09/15/zombies-run-managing-page-transitions-in-backbone-apps/ --beこの投稿のJohnnyOshikaからのコメントを必ず読んでください。彼は、モデルとコレクションのイベントを処理する簡単な方法を示す非常に便利なStackOverflowの回答を示しています。

于 2012-04-17T01:45:22.123 に答える