关于javascript:BackboneJS视图渲染延迟,在iPhone 4s(iOS 8)上,2015年

BackboneJS view rendering delay, on iPhone 4s (iOS 8), 2015

我正在使用BackboneJS(jQuery Underscore)制作一个单页的Web应用程序,并且正在各种浏览器和各种设备上对此进行测试。最终它将成为Phonegap应用。

效果很好,但是在iPhone 4s(iOS 8)上,我所有的路线渲染速度都很慢(大约一秒钟)。我尚未解决300毫秒的点击延迟,但稍后会担心。我的一条路线使问题变得更加严重,该路线的视图数量特别多(?30),并且可能需要5秒钟才能在此设备上进行渲染。

这是我的路线示例:

1
2
3
4
'some_route': function(){
  if(APP.controller) APP.controller.destruct();
  APP.controller = new SomeController();
},

所有视图都在控制器实例化期间实例化并呈现(并且应分别更新DOM)。这是一个视图渲染函数的示例,该路由加载时会调用许多视图:

1
2
3
4
render: function() {
  var modelData = this.model.toJSON();
  this.$el.html(this.template(modelData));
},

有趣的是,如果我在路由的控制器实例下添加了警报,则它会在UI更改出现之前(3-4秒之前)发生。并且,所有UI更改都将立即显示。鉴于JavaScript是单线程的,这没有多大意义。除非jQuery以某种方式异步处理.html()调用,否则浏览器将延迟应用于可视DOM更新...

我在模板的末尾附加了一个时间戳(因此每个视图的末尾都带有时间戳),以查看执行每个视图需要花费多长时间。第一个和最后一个之间的差异仅为0.03s,但是浏览器仍然需要将近5秒钟才能将更改实际呈现到屏幕上(在此期间,它没有响应)。

我仔细研究了render函数,发现执行以下操作可以大大提高性能,但是并不能解决我的问题:

1
2
3
4
5
render: function() {
  var modelData = this.model.toJSON();
  this.template(modelData); //call anyway to gauge performance impact
  this.$el.html('');        //call anyway, but with nothing
},

这可能是内存问题吗?与Backbone 导航(URL更改)有关吗?还有其他人遇到吗?我已经四处搜寻,但我真的没有运气找到任何遇到相同问题的人。

更新

为视图元素简单地添加display:none实际上也大大提高了速度。显然并不能解决问题,但是它看起来比其他任何东西都更像是一个内存问题。我将尝试通过CSS和图像优化来加速此过程,并将在可行的情况下发布解决方案。


您有多少次观看?如果在实例化控制器时呈现了所有视图(这可能是一个缓慢的功能),请尝试添加类似这样的内容以检查花费的时间

1
2
3
4
    var timeStart = performance.now();
    APP.controller = new SomeController();
    var timeEnd = performance.now();
    console.log('time ' + (timeEnd - timeStart) + ' ms');

的确JavaScript是单线程的,但是您必须记住浏览器如何执行所有任务,请查看该问题的第二个答案为什么setTimeout(fn,0)有时有用?。


我找到了两种解决方案。

首先,页面上有沉重的背景图像。注释掉这些CSS,并为麻烦的路径删除正在加载的视图的CSS,将延迟减少了一半。减少应用程序正在使用的资源(甚至是背景图像)似乎可以直接减少延迟。

因此,一种解决方案是优化图像和CSS。使用的内存越少越好。

其次,我发现可以在路线转换期间显示加载屏幕,从而大大降低了UX的影响。我正在使用这样的东西:

1
2
3
4
5
6
7
8
'some_route': function(){
  $('#overlay').show();
  setTimeout(function(){
    if(APP.controller) APP.controller.destruct();
    APP.controller = new SomeController();
    $('#overlay').hide();
  },30);
},

这样,浏览器有时间在视图渲染受到冲击之前显示加载叠加层-这似乎是造成延迟的原因-最后它会删除叠加层。

当然,如果在浏览器完成VISUALLY呈现更改后(不仅仅是在javascript执行结束之后)发生了某个事件,可以用一种更好的方法来完成。