重用主干视图

Reusing Backbone Views

本文关键字:视图      更新时间:2023-09-26

我正在编写一个用户以线性方式移动的 Backbone 应用程序。该应用程序的工作方式类似于电视节目,旁白引导用户从一个场景到另一个场景的剧集。

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

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

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

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 中。

谁能帮我确定这种方法的优缺点?具体来说,我关心的是尽可能的最佳性能,以及避免内存泄漏,因为保留对这些对象的引用的副作用是我(或可能不会)再次使用。

谢谢。

除非您正在构建一个真正资源密集型的应用程序,否则这可能是过早的优化。 我会使用最简单的方法,如果性能证明是一个问题,我会稍后优化代码。

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

  • (重新)构建场景所需的时间。
  • 非活动场景将使用的内存量
  • 场景的使用频率
  • 总共有多少场景

如果构建场景的速度足够快,以至于用户不会注意到,并且不涉及下载或加载额外的资源,那么每次都重新渲染视图可能没问题。 但是,如果渲染需要一段时间,那么也许您应该考虑保留视图。 同样,我肯定会保留一个可能重复使用的资源缓存。

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

如果您真的担心使用太多内存,那么您可以随时缓存一些视图而不是所有视图 - 要么通过它们被重用的可能性,要么通过某种"最新视图"方案,其中最近的 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 中删除。这可以与您的缓存策略结合使用,或者如果事情趋向于变化,您根本不需要缓存任何内容(同时由其他用户并且您不想实现轮询或尚未实现服务器端推送)。如果/当我知道我将有太多可能导致内存使用/泄漏从而降低性能的对象时,我会使用此策略。

希望这对:)有所帮助