我正在编写一个Backbone应用程序,用户以线性方式浏览。该应用程序的工作方式类似于电视节目,其中叙述引导用户通过场景之间的剧集。
为了实现这个目标,我有一个父Episode视图,负责在正确的时间加载正确的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);
}
基本上,如果scene数组的索引与当前sceneIndex
匹配,只需将该视图加载到dom中。否则,创建它,在scene数组中保留对它的引用并将其加载到DOM中。
任何人都可以帮我确定这种方法的专业和缺点吗?具体来说,我担心可能的最佳性能以及避免内存泄漏,因为这是保持对我(或可能不会)再次使用这些对象的引用的副作用。
感谢。
答案 0 :(得分:4)
除非您正在构建真正资源密集型应用,否则这可能是过早优化。我只想采用最简单的方法,如果性能证明是一个问题,请稍后优化代码。
除此之外,可能没有绝对正确的答案。您需要权衡几个因素:
如果构建场景足够快以至于用户不会注意到,并且不涉及下载或加载额外资源,那么每次重新渲染视图可能会很好。但是,如果渲染需要一段时间,那么也许你应该考虑保持观点。同样,我肯定会保留可能重复使用的资源缓存。
另一方面,我猜你的观点将会使用非常少量的内存(特别是与大多数机器和手机最近的RAM相比),所以将它们保存在内存中可能不是这将是一个很大的问题(除非你认为你的数千个仍然在内存中 - 真的取决于你认为用户将在一个会话中与多少视图交互)
如果您真的担心使用太多内存,那么您可以随时缓存一些视图而不是所有视图 - 无论是重新使用它们的可能性,还是某种“最近的”视图的方案,其中最近的20(或其他)视图存储在内存中,其余视图在需要时构建。然而,这有点复杂,而且可能有点过分。
答案 1 :(得分:1)
实际上,你显然知道它但需要确认,你建议的是应该做什么,视图应该只创建一次然后在需要时渲染,至于内存需求它只取决于你的场景总数但是,我仍然无法想象一个浏览器会放弃的情况,因为它耗费了记忆力,因此,在我的拙见中,你的工作非常好,我就是这样做的。
答案 2 :(得分: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中移除。这可以与您的缓存策略一起使用,或者如果事情往往发生变化,您根本不需要缓存任何内容(由其他用户同时进行并且您不想实现轮询或者没有实现服务器端推送)。如果/当我知道我将有太多的对象可能导致内存使用/泄漏可能会降低性能时,我会使用此策略。
希望这会有所帮助:)