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

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

我正在使用 BackboneJS(jQuery + Underscore)制作一个单页网络应用程序,我正在各种浏览器和各种设备上测试它.最终它将成为一个 Phonegap 应用程序。

效果很好,但是在 iPhone 4s (iOS 8) 上,我所有的路由渲染都非常慢(大约一秒左右) .我还没有解决 300 毫秒的点击延迟问题,但稍后我会担心这个问题。我的一条路线使问题变得更糟,该路线的观看次数特别多 (~30),并且最多可能需要 5 秒才能在此设备上呈现

这是我的路线示例:

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

所有视图都在控制器实例化期间实例化和呈现(并且应该单独更新 DOM)。下面是一个视图渲染函数的例子,当这个路由加载时,它被调用用于多个视图:

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

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

我在模板的末尾附加了一个时间戳(因此每个视图在末尾都带有一个时间戳)以查看每个视图执行所花费的时间。第一个和最后一个之间的差异 仅 0.03 秒,但浏览器仍需要将近 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 和图像优化来加快速度,如果可行,我将 post 提供解决方案。

我找到了两个解决方案。

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

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

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

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

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

当然,如果有一个事件在浏览器完成视觉呈现更改后发出(而不是在 javascript 执行结束后),这可以用更好的方式完成。

你有多少浏览量?如果在实例化可能是一个慢函数的控制器时呈现所有视图,请尝试添加类似这样的内容来检查它花费的时间

    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?