3

我正在编写一个用户以线性方式移动的 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 中。

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

谢谢。

4

3 回答 3

4

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

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

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

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

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

如果您真的担心使用过多的内存,那么您总是可以只缓存一些视图而不是所有视图 - 无论是通过它们被重用的可能性,还是某种“最近的视图”方案最近的 20 个(或其他)视图存储在内存中,其余的在需要时构建。然而,这有点复杂,而且很可能是矫枉过正。

于 2013-10-17T20:57:24.260 回答
1

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

于 2013-10-17T20:38:59.573 回答
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 中移除。这可以与您的缓存策略一起使用,或者如果事情倾向于更改(同时由其他一些用户并且您不想实现轮询或尚未实现服务器端推送),则您根本不需要缓存任何东西。如果/当我知道我将拥有太多可能导致内存使用/泄漏从而降低性能的对象时,我会使用此策略。

希望这可以帮助 :)

于 2013-10-18T01:29:36.747 回答