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

时间:2015-08-06 11:20:07

标签: javascript jquery ios performance backbone.js

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

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

以下是我的路线示例:

if(res != CURLE_OK) {
 fprintf(stderr, "curl_easy_perform()failed:%s\n",curl_easy_strerror(res));}

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

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

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

我在模板的末尾添加了一个时间戳(因此每个视图在末尾都会显示一个时间戳),以查看每个视图执行的时间长度。第一个和最后一个之间的差异是仅0.03s ,但浏览器实际上将更改实际呈现在屏幕上仍然需要几乎 5秒(在此期间,它没有反应)。

我使用了渲染功能,发现执行以下大幅提升了性能,但它并没有解决我的问题:

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

这可能是内存问题吗?是否与骨干导航(URL更改)有关?还有其他人遇到过这个吗?我已经四处寻找了,但是我找不到任何有同样问题的人真的很幸运。

更新

简单地为视图元素添加render: function() { var modelData = this.model.toJSON(); this.template(modelData); //call anyway to gauge performance impact this.$el.html(''); //call anyway, but with nothing }, 实际上也大大提高了速度。显然没有解决问题,但它开始看起来更像是一个内存问题而不是其他任何问题。我将尝试通过CSS和图像优化加快速度,并且如果有效的话,我会发布一个解决方案。

2 个答案:

答案 0 :(得分:1)

我找到了两个解决方案。

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

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

其次,我发现可以在路由转换期间显示加载屏幕,从而显着降低用户体验的影响。我使用的是这样的东西:

'some_route': function(){
  $('#overlay').show();
  setTimeout(function(){
    if(APP.controller) APP.controller.destruct();
    APP.controller = new SomeController();
    $('#overlay').hide();
  },30);
},

这样,浏览器就有时间在视图渲染的冲击之前显示加载叠加层 - 这似乎会导致延迟 - 最后它会删除叠加层。

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

答案 1 :(得分:1)

你有多少次观看?如果在实例化可能是慢速函数的控制器时呈现所有视图,请尝试添加这样的内容以检查所需的时间

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

确实,JavaScript是单线程的,但您必须记住浏览器如何执行所有任务,请查看此问题的第二个答案Why is setTimeout(fn, 0) sometimes useful?