Javascript 重用主干视图

Javascript 重用主干视图,javascript,backbone.js,Javascript,Backbone.js,我正在编写一个主干应用程序,用户可以以线性方式移动。该应用程序的工作原理类似于一个电视节目,其中的叙述引导用户从一个场景到另一个场景 为了实现这个目标,我有一个父情节视图,负责在正确的时间加载正确的场景视图。到目前为止,我对这个功能感到满意 我需要添加一个功能,用户可以在空闲时从一个场景跳到另一个场景。可能在应用程序的整个生命周期内多次查看同一场景。我的问题是,我是否应该在每次加载同一场景时创建一个新的场景视图,还是应该创建一个场景实例,然后在用户第二次、第三次或第四次加载时重新使用它 下面的示

我正在编写一个主干应用程序,用户可以以线性方式移动。该应用程序的工作原理类似于一个电视节目,其中的叙述引导用户从一个场景到另一个场景

为了实现这个目标,我有一个父情节视图,负责在正确的时间加载正确的场景视图。到目前为止,我对这个功能感到满意

我需要添加一个功能,用户可以在空闲时从一个场景跳到另一个场景。可能在应用程序的整个生命周期内多次查看同一场景。我的问题是,我是否应该在每次加载同一场景时创建一个新的场景视图,还是应该创建一个场景实例,然后在用户第二次、第三次或第四次加载时重新使用它

下面的示例显示了到目前为止我是如何重用场景的

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中

有人能帮我找出这种方法的利弊吗?具体地说,我关心的是尽可能获得最佳性能,以及避免内存泄漏,这是保留对这些对象的引用的副作用,而我的对象(或可能不会)会被再次使用


谢谢。

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

除非你正在构建一个真正的资源密集型应用程序,否则这可能是过早的优化。我会选择任何最简单的方法,如果性能出现问题,我会在以后对代码进行优化

除此之外,可能没有一个绝对正确的答案。您需要权衡以下几个因素:

  • 重建场景所需的时间
  • 非活动场景使用的内存量
  • 场景的使用频率如何
  • 总共有多少个场景
如果构建场景的速度足够快,用户不会注意到,并且不需要下载或加载额外的资源,那么每次重新渲染视图就可以了。但是,如果渲染需要一段明显的时间,那么您可能应该考虑保留视图。同样,我肯定会保留一个可以重复使用的资源缓存

另一方面,我猜您的视图将使用非常少的内存(特别是与现在大多数机器和手机的内存相比),因此将它们保留在内存中可能不是什么大问题(除非您认为最终会有数千个视图仍保留在内存中-这实际上取决于您认为用户在单个会话中将与多少个视图交互)


如果你真的担心使用太多的内存,那么你总是可以缓存一些视图,而不是所有视图——或者根据它们被重用的可能性,或者某种“最近的视图”方案,其中最近的20个(或其他)视图视图存储在内存中,其余的视图在需要时构造。但是这有点复杂,而且很可能是多余的。

是什么阻止了您提前创建所有视图并在运行时从缓存的数组中获取它们?您的视图真的是资源密集型的吗?如果是,缓存是有意义的您的上述方法很好。如果不是,我会立即创建它们(无缓存/重用),或者预先创建所有它们(在数组中缓存引用),然后在运行时获取它们。如果您担心性能/内存泄漏的使用,可以使用以下方法:

   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中移除。这可以与缓存策略一起使用,或者,如果情况有变,您根本不需要缓存任何内容(同时由其他用户执行,并且您不希望实现轮询或尚未实现服务器端推送)。如果/当我知道我将有太多对象,可能导致内存使用/泄漏,从而降低性能时,我会使用此策略


希望这有帮助:)

感谢您的见解。重新创建模板很容易;代码很简单,因此代码很少会出错。但不要担心模型的内存问题。图像、视频和DOM会占用更多内存。如果您对其进行测试,但速度不够快,则您会希望更新DOM,而不是重新创建模板。I've一直在为主干网开发PreView(),它有一个简单的界面,如果您需要更高的性能,可以重用模板。感谢您的输入。我在close函数方面有类似的功能。感谢您的反馈。听到您理解一个概念总是很高兴。