Backbone.jsのイベントを管理してゾンビviewを回避する

Backbone.jsのイベントの管理についての個人的なメモ。

イベントの管理

画面遷移しないアプリなどでは、Backbone.jsではviewオブジェクトにbindしたイベントを自前管理することが重要になる。
viewオブジェクトはそれぞれが独立しつつも、相互バインドしあう関係であることが理想的。

しかし、イベント管理がうまくいっていないと、削除したはずなのに再び生成されるゾンビのようなviewが残ることになる。
この辺りをふまえて、個人的なやり方をメモ。

まずは基礎となるviewのclass

[ruby]
class Animal extends Backbone.Views

継承するclass間でイベントを集約するプロパティ

vent: _.extend {}, Backbone.Events

自前でイベントを解除するメソッド

close: ->
@model.off null, null, this if @model && @model.off
@collection.off null, null, this if @collection && @collection.off
@vent.off()
@undelegateEvents()
[/ruby]

上記のclassを継承したclass同士はventプロパティを通じてイベント相互作用する。
これにより、直接viewオブジェクト同士が参照を持つことなくイベント駆動でそれぞれのイベントを発火することができる。

また、不要になったviewを削除する場合は、viewが参照しているmodelやcollectionのほかにバインドしているイベントも削除することが重要。

ちなみにBackbone.jsではイベントのバインド関連はのメソッドは以下になる。

  • bind / unbind
  • on / off
  • listenTo / stopListening
  • once, listenToOnce (一度だけイベントにバインド)

メモリー・リークの原因

JavaScriptではどこからも参照されていないオブジェクトはガーベッジ・コレクションによって回収さて、メモリーは解放される仕様なので、viewオブジェクトがメモリ上から削除されないでゾンビのように生き返るのはそのオブジェクトへの参照が有効になっているのが原因。

メモリー・リークするview

たとえば参照を残したままの状態では

変数zombieにnullを代入しても、deleteしても、イベントが発火する。
これは変数zombie(windowのプロパティ)は削除されたが(オブジェクトへの参照が削除されただけ)、ventプロパティの参照が残っているためメモリから削除されず、イベントの発火とともに蘇ることになる。

class継承と相互バインド

ということで、Baseのclassを継承したview classを作成して、それぞれでイベントやり取りする。
さらに自前のイベント削除機能で奇麗に削除する。

[ruby]
class Animal extends Backbone.View
vent: _.extend {}, Backbone.Events

close: ->
@model.off null, null, this if @model && @model.off
@collection.off null, null, this if @collection && @collection.off
@vent.off()
@undelegateEvents()

class Cat extends Animal
initialize: ->

# 継承もとのイベントを拡張
@events = _.extend @events, Animal::events
# イベントが通知されたら発火
@vent.on "animal", @barks, @

super

barks: (dog_barks) ->
console.log dog_barks
console.log "meow"
@close()

class Dog extends Animal

initialize: ->
@events = _.extend @events, Animal::events

super

barks: ->
@vent.trigger "animal", "bow"
@close()

cat = new Cat()
dog = new Dog()
dog.barks()

[/ruby]

close メソッドを自前で用意して、イベントのbindを管理することにより特定のviewオブジェクトのイベントの参照をきちんと削除することで、ゾンビの様なviewを発生しないようにできている。

class継承時のコツ

class継承したときに、backbone.jsの場合は constractorのsuper をたどって継承もと(スーパークラス)にアクセスできる。(プロトタイプチェーンがprotoをたどる様な感じ)
coffeescriptだと super() メソッドを使うことでと継承元クラス(スーパークラス)の同名メソッドを呼べるので、これを利用することでメソッドを拡張できる。

また、functionオブジェクトはsuperメソッドで継承、拡張できるが、プロパティは継承できずに上書きされる。
そこでプロパティに関しては、継承元(スーパークラス)のプロトタイプをたどって、underscore.jsのextendメソッドで拡張している。

[ruby]
class Dog extends Animal

initialize: ->

# 継承元classのeventsも継承
@events = _.extend @events, Animal::events

# 継承元classの同名のメソッド呼ぶ
super

[/ruby]

という感じで、Backboneだとviewを継承するとviewの管理が大変になるが、イベントの管理をなんとかできるとある程度簡単に開発できそうです。

参考にしたサイト
http://lostechies.com/derickbailey/2012/04/03/revisiting-the-backbone-event-aggregator-lessons-learned/
http://lostechies.com/derickbailey/2011/09/15/zombies-run-managing-page-transitions-in-backbone-apps/

Comments