应用程序停止时添加加载指示符

时间:2015-08-06 17:46:50

标签: javascript ember.js ember-cli

我有一个动作导致应用程序挂起几秒钟。我想添加一些加载指示器来表明它正在做某事,而不仅仅是冻结。

我已经尝试了几件事,其中一些是我认为无法完成的完整实验。

首先,这是我在尝试添加任何指标之前所拥有的:

filterObserver: function(){
  // we needed the debounce because it would crash the app if it took too long
  // it has to filter through ~10,000 records

  Ember.run.debounce(this, this.filterFoo, 1500); 
}.observes('filterValue'),

我认为这会起作用,但它似乎等到观察者中的所有内容都在重新呈现页面之前完成:

controller.js

isLoading: false,
filterObserver: function(){
  this.set('isLoading', true);

  Ember.run.debounce(this, this.filterFoo, 1500);

  this.set('isLoading', false);
}.observes('filterValue'),

template.hbs

<ul class="project-list {{if isLoading 'loading'}}">
{{#each group in foo}}
  {{group-item group=group}}
{{/each}}
</ul>

所以,我想也许我需要强迫它重新渲染以显示变化。我将整个列表移动到一个组件,以便能够访问组件的rerender方法:

component.js

export default Ember.Component.extend({
  loadingObserver: function() {
    this.rerender();

    Ember.run.schedule('afterRender', this, function() {
      this.sendAction('filterAll');
    });
  }.observes('isLoading')
});

controller.js

actions: {
  filterAll: function() {
    Ember.run.debounce(this, this.filterActivities, 1500);
    this.set('isLoading', false);
  }
}

所以,我想也许Ember的跑步循环可行。到目前为止,我非常沮丧,但我想尝试一切可能有效的方法:

component.js

export default Ember.Component.extend({
  loadingObserver: function() {
    this.rerender();

    Ember.run.schedule('afterRender', this, function() {
      this.sendAction('filterAll');
    });
  }.observes('isLoading')
});

这些都没有奏效。

我知道不同的路由方法,例如afterModeldestroy等。此页面已经加载了我的页面,因此在这种情况下,这些方法都不起作用。

我相信这是因为在重新渲染模板之前,Ember会等到观察者中的所有内容都完成。所以,我需要一些方法让它在模板中发生任何变化时显示这个指标,或等待它完成设置变量并在继续执行动作代码之前添加类。

思考?想法?

为了记录,我知道1.13引入了微光,这将有助于应用程序挂起。但是,我们依赖于几个仍然使用1.11的插件,所以我担心我们暂时会坚持使用它。

1 个答案:

答案 0 :(得分:0)

修改

显然run.later仅适用于我的情况,因为我也使用run.debounce。下面的代码在我的特定情况下不起作用,因为run.next认为run.debounce代码在没有完成时已完成。这应该适用于大多数情况:

Ember.run.once(this, function() {
  this.set('isLoading', true);
});

Ember.run.next(this, function() {
  // your code here
  // `isLoading` will be true while this is running,
  // so your loading indicator will still be present

  this.set('isLoading', false);
});

如果您需要在Ember的运行循环之外运行指示符,我的原始答案仍然有效。但是,您可能能够在绝大多数时间使用上面的代码。

原始答案

我实际上能够解决这个问题。我只是使用Ember.run.later让Ember等到所有其他异步事件结束。在我的应用中,这简直相当于:

var _this = this;
this.set('isLoading', true);

Ember.run.debounce(this, this.filterFoo, 1500);
Ember.run.later(function() {
  _this.set('isLoading', false);
}, 1500); // I set the timeout to 1500 ms because that's the same as the debounce

我发现这被埋在Ember的指南中:A SPINNING BUTTON FOR ASYNCHRONOUS ACTIONS。您可以在Ember's docs中详细了解run.later

如果我没有这样做,它会尝试一次执行所有代码。这基本上只是让它等到它完成或超时。