Twitter小部件在骨干视图上泄漏内存

时间:2014-07-21 17:38:49

标签: javascript backbone.js twitter coffeescript

我使用骨干和coffeScript构建网站,当我从一个部分(内部页面)更改为另一个部分时,我将替换新布局上呈现的视图,并在旧部分上调用close方法。一切似乎工作得很好,除了在主视图上再次渲染小部件,我需要调用twttr.widgets.load(),并且每次创建一个新的小部件,但似乎旧的小部件被保留,它没有&#39 ;无论如何我删除视图或iframe节点,或使容器元素为空。我已经尝试在删除视图之前分离小部件,将其存储在变量上,并在再次调用主视图时使用它来放置小部件,而无需调用load方法,但iframe元素是唯一的保留在变量中的东西(即使在删除视图之前它已经包含了所有内容),我已经尝试克隆节点,使用iframe内容,到目前为止一切都失败了。我似乎找不到在twttr obj中卸载twitter小部件的方法,所以我最后会遇到令人讨厌的内存泄漏,每次加载主视图时它总计增加3mb,所以这是不是一个选项,特别是对于移动设备,我最终可以将100mb分配给鬼小部件。

root = window ? global

root.Backbone.View::close = ()->
  @remove()


class Otalvaro.Views.BaseContent extends Backbone.View

  initialize: ->
    @model.bind('sync', @render, this)

这是我的主页视图(在此版本中,我试图保存iframe内容,正常版本,不检查inMemory使用@remove()关闭视图并直接删除iframe)

编辑注意:删除视图并非在此处工作,因为在每个新的实例中,小部件都会创建一个新的iframe(小部件ID甚至会增加),所以我&#39 ;我试图只保留内存中的主视图,因为内存中的iframe比30个鬼iframe更好。

class Otalvaro.Views.Home extends Otalvaro.Views.BaseContent
  template: root.template('homeTemplate')

  initialize: ->
    super
    @inMemory = no

  closeTwitterWidget: ->
   $('iframe').unbind().remove()

  close: =>
    @$el = @$el.clone()
    @el = @$el[0]
    @iframe = @$el.find('iframe').contents()
    @inMemory = yes

  render: (callback)->
    if(@inMemory)
      console.log '@iframe', @iframe
    else
      console.log 'not in memory, doing normal rendering'
      if _.isEmpty(@model.toJSON())
        console.log 'model is empty, fetching it now'
        @model.fetch()
      else
        console.log 'model fetched, now rendering'
        @$el.html( @template(@model.toJSON()) )
        # With out the delay, the widget won't load everytime
        _.delay( ->
            console.log 'firing twttr.widgets.load()'
            root.twttr.widgets.load() # <- Guilty of all charges
        , 630)
        if callback? then callback(@el)

    this

这是layoutView代码的一部分,它会在路径更改时呈现视图:

class Otalvaro.Views.MainLayOut extends Backbone.View
  el: '#mainContent'

  closeOldViews: ->
    if @oldViews?
      for view in @oldViews
        console.log 'view to be closed', view
        view.close()

  ###
  # Takes an array containing one or more view instance as argument, adds a fadeOut fx to hide the current content
  # then it renders each view instance from the array and extracts its node element (el) and pushes it into an array
  # that is later (after the fadeIn completes) added as the html content of the layoutView
  ###
  show: (views)->
    @fadeOut()
    delay = 500 
    viewNodes = []

    for view in views
      node =  view.render().el
      viewNodes.push(node)

    _.delay(
      _.bind ->
        @closeOldViews()
        @$el.html(viewNodes)
        @fadeIn()
        @oldViews = views
   , this
delay)

用于家庭的路由器处理程序,使用已经实例化的视图,(也尝试在路由更改时实现主视图,但没有帮助)

 home:->
    @mainLayout.show([@homeView])
    null

修改:已添加 - &gt;主页模板

<script id="homeTemplate" type="text/x-handlebars-template">
    <blockquote id="homeQuote">
        <p>Some Quote</p>
        <footer>Catalina Otalvaro</footer>
    </blockquote>
    <div class="twitterFeed fadeIn">
        <a href="https://twitter.com/kataotalvaro" data-widget-id="481647155510140928" class="twitter-timeline">Tweets by @kataotalvaro</a>
    </div>
</script>

我已经在tiwtter开发者论坛上阅读了这几个主题,但他们没有得到回复,而且我对此并不是很有经验,所以如果有人对我如何解决这个问题有任何建议,我非常感谢,感谢您花时间阅读我的问题:)

https://dev.twitter.com/discussions/30128 https://dev.twitter.com/discussions/5957

2 个答案:

答案 0 :(得分:0)

close中的Otalvaro.Views.Home方法覆盖了基本close方法,这意味着每次关闭该主视图时,您实际上并未删除该视图,而且,你正在克隆元素:

@$el = @$el.clone();

closeTwitterWidget可能会通过删除iframe来帮助解决其中一些问题,但我看不到它被调用的位置。

尝试将家庭视图中的close方法更改为@remove()并查看其进展情况。

此外,Twitter小部件肯定会加载到您家庭视图的元素内吗?

答案 1 :(得分:0)

我设法通过在我的视图的属性中存储窗口小部件(<div>在窗口小部件iframe中)来解决此问题,以使窗口小部件不像存储文档中的任何节点那样简单,并且必须在iframe容器(主容器)为空或iframe也为空之前进行存储。现在这条路径上的主要问题是将窗口小部件重新添加到视图中,但我发现将html内容添加到当前不在DOM上的iframe是不可能的(或者似乎是这样),因为那是我的因为iframe实际上只是在视图的模板中,我决定将小部件附加到div,然后我需要的是将iframe样式添加到我的主要样式(有一些修改),现在当我重新渲染我的主视图是从记忆中获取元素并且没有内存泄漏,我在导航时获得大约6mb的顶部并且从不上升,使用widget.load()它高达50mbs。我不认为这是一个理想的解决方案,它实际上是一个黑客,twitter应该提供一种卸载小部件的方法,而不仅仅是加载方法。如果有人在同一个地方,我希望这会有所帮助。感谢@glortho花时间回答=)

以下是修改后的主页视图

class Otalvaro.Views.Home extends Otalvaro.Views.BaseContent
  template: root.template('homeTemplate')

  initialize: ->
    super
    @inMemory = no
    @memoryRender = no

  close: =>
    unless @inMemory
      @$iframe = $( $('.twitter-timeline').contents().find('body').html() )
      @inMemory = yes

  render: (callback)->
    unless @memoryRender
      if(@inMemory)
        @$el.find('.twitterFeed').html(@$iframe)
        @memoryRender = yes
      else
        console.log 'not in memory, doing normal rendering'
        if _.isEmpty(@model.toJSON())
          console.log 'model is empty, fetching it now'
          @model.fetch()
        else
          console.log 'model fetched, now rendering'
          @$el.html( @template(@model.toJSON()) )
          _.delay( ->
              console.log 'firing twttr.widgets.load()'
              root.twttr.widgets.load()
          , 630)
          if callback? then callback(@el)

    this