重用Backbone视图

3
我正在编写一个使用Backbone框架的应用程序,用户可以按线性顺序移动。这个应用程序的工作方式类似于电视节目,即叙述引导用户从场景到场景。
为了实现这个目标,我有一个父级“Episode”视图,负责在正确的时间加载正确的“Scene”视图。到目前为止,我对这个功能感到满意。
我需要添加用户随意跳过场景的能力。在应用程序的生命周期内,可能会多次查看同一场景。我的问题是,当用户第二、第三或第四次加载场景时,我是否应该创建新的“Scene”视图,还是应该创建场景的实例,然后在重复使用它。
下面的示例显示了我迄今为止如何重复使用场景。
loadSceneView: function()
{
    var sceneIndex = this.model.getCurrentIndex();

    if(this.scenes[sceneIndex])
    {
        this.scenes[sceneIndex].render();
        console.log('Scene: ' + sceneIndex + ' already loaded. Reusing');
    }
    else
    {
        console.log('Loading Scene: ' + sceneIndex);

        switch(sceneIndex)
        {
            case 0:

                this.scenes[sceneIndex] = new cith.Views.Scene1();
                break;

            case 1:

                this.scenes[sceneIndex] = new cith.Views.Scene2();
                break;

            case 2:

                this.scenes[sceneIndex] = new cith.Views.Scene3();
                break;
        }
    }

    this.currentScene = this.scenes[sceneIndex];
    this.listenTo(this.currentScene, 'scene:ended', this.goToNextScene);

    $('#scene').html(this.currentScene.el);
}

基本上,如果场景数组中有与当前sceneIndex匹配的索引,则将该视图加载到dom中。否则,创建它,将其引用保留在场景数组中,并将其加载到DOM中。
有人能帮我确定这种方法的优缺点吗?具体来说,我关心的是尽可能获得最佳性能以及避免因保留对这些对象的引用而导致的内存泄漏(或者可能不会再次使用)。
谢谢。
3个回答

4
除非你正在构建一个非常资源密集型的应用程序,否则这可能是过早的优化。我会选择最简单的方法,如果性能证明是个问题,再进行代码优化。
除此之外,这可能并没有绝对正确的答案。你需要权衡几个因素:
- (重新)构建场景所需的时间。 - 闲置场景使用的内存量。 - 场景使用的频率。 - 总共有多少场景。
如果构建场景足够快,用户不会注意到,并且不涉及下载或加载额外的资源,则每次重新渲染视图可能就足够了。但是,如果渲染需要花费显著的时间,那么也许你应该考虑保留视图。同样地,我肯定会保留可能被重复使用的资源缓存。
另一方面,我猜测你的视图将使用非常少的内存(特别是与大多数机器和手机上的几GB RAM相比),因此将它们保存在内存中可能不会成为太大的问题(除非你认为你将在内存中保留数千个视图——这实际上取决于你认为用户在单个会话中会与多少视图交互)。
如果你真的担心使用太多内存,那么你可以只缓存一些视图而不是所有视图——可以根据它们被重复使用的可能性,或者通过一些“最近视图”方案,其中最近的20个(或其他数量)视图存储在内存中,其余视图在需要时构建。然而,这可能有点复杂,也可能过度了。

重新创建模板很容易;代码很简单,所以你的代码很少会出错。但是不要担心你的模型内存问题。图像、视频和DOM将比任何东西都占用更多的内存。如果测试后发现速度不够快,那么您将希望更新DOM而不是重新创建模板。我一直在为backbone开发PrefView(https://github.com/puppybits/BackboneJS-PerfView),它具有一个简单的界面,可以重复使用模板,如果您需要更好的性能。 - puppybits

1

你为什么不直接创建所有视图,并在运行时从缓存数组中获取它们呢?你的视图真的那么耗资源吗?如果是,缓存是有意义的,你上面的方法很好。如果不是,我会选择动态创建它们(不缓存/重用)或者预先创建所有视图(在数组中缓存引用),然后在运行时只需获取它们。如果你担心性能/内存泄漏问题,可以使用以下代码:

   var dispatcher = _.clone(Backbone.Events); //Event-bus for all the views to talk to each other

/*
 * Create a BaseView for all classes to inherit from. "Intercept" Backbone's constructor
 * by providing a hook for any custom initialization that needs to be done across views.
 */
    //reference to Backbone.View's constructor
    var ctor = Backbone.View;
    //extend Backbone.View
    var BaseView = Backbone.View.extend({
        //override the constructor property
        constructor: function(options){
            //call Backbone.View's constructor (ctor) and just proxy the arguments to it
            ctor.apply(this, arguments);
            //perform initialization here
            dispatcher.on('close',this.close, this);
        },

        //Adding a custom close method inheritable by all 'children' of BaseView. 
        close: function(){
            //if an onClose 'handler' is defined by the class execute it - for any custom 'close' logic to be called
            if(this.onClose)
                this.onClose();

            this.off();
            this.undelegateEvents();
            this.remove();
        }
    });

您可以为所有视图创建一个“基类”,其中包含一个close()方法,该方法将视图与相应的模型和事件解绑,并从视图/DOM中删除自身。如果事情往往会发生变化(由其他用户同时更改,并且您不想实现轮询或尚未实现服务器端推送),则可以与缓存策略配合使用;否则,您无需缓存任何内容。如果我知道将有过多的对象可能导致内存使用/泄漏而减慢性能时,我会使用此策略。

希望这有所帮助:)


谢谢您的输入。就关闭函数而言,我有类似的东西。 - adampetrie

1

实际上,你显然已经知道了,但需要确认的是,你建议的是应该做的事情,视图应该只创建一次,然后在需要时进行渲染,至于内存需求,它仅取决于您拥有的场景总数,但仍然,我无法想象一个浏览器会因为耗尽内存而放弃,所以,在我看来,你的工作非常好,这也是我会这样做的方式。


感谢您的反馈。听到您理解了一个概念,总是很不错的。 - adampetrie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接