0

我在 Ember 控制器中的操作处理有问题。在 hbs 中单击编辑按钮后,我想连续运行某些功能。我已经尝试过这样的操作。

openEditWindow() {
  this.set('someChangingValue', true);
},

这是对动作someChangingValue变化做出反应的函数。

someChangingValue: false,
  someTestFunction: observer('someChangingValue', function() {
  var test = this.get('someChangingValue');

  if(test === true){
    Ember.run.later((function() {
      this.functionThatIsRunningEachTwoSeconds();
    }), 2000);
  } else {
    console.log('this should not do anything');
  }
}),

但这只运行functionThatIsRunningEachTwoSeconds一次。还尝试了更改someChangingValuefalseiftrue和 else 的相同功能,这使我陷入了观察属性的无限循环。

谢谢!

4

2 回答 2

0

Ember.run.later只运行一次函数。文档中说得很清楚

另外,您使用非常旧版本的 ember 吗?Ember.run.later已过时,您应该使用部分导入import { later } from '@ember/runloop';代替

至于你的任务,至少有两种方法

使用 ember-concurrency 插件

安装ember-concurrency并写入控制器:

import { task, timeout } from 'ember-concurrency';

export default Controller.extend({
  infiniteTask: task(function* () {
    while(true) {
      this.functionThatIsRunningEachTwoSeconds();
      yield timeout(2000);
    }
  }).drop(),
});

模板:

{{#if infiniteTask.isIdle}}
  <button onclick={{perform infiniteTask}}>Start</button>
{{else}}
  <button onclick={{cancel-all infiniteTask}}>Stop</button>
{{/if}}

这个插件在很多情况下都有帮助,阅读它的文档来了解你为什么需要它

创建一个递归调用自身的函数

这是一种经典的 JS 方法来重复一些动作,但在 vanilla JS 中我们使用setTimeout而不是 ember 的later.

import { later, cancel } from '@ember/runloop';

export default Controller.extend({
  infiniteFuction() {
    this.functionThatIsRunningEachTwoSeconds();
    this.set('infiniteTimer', later(this, 'infiniteFuction', 2000));
  },
  startInfiniteFunction() {
    //clear timer as safety measure to prevent from starting few 
    //"infinite function loops" at the same time
    cancel(this.infiniteTimer);
    this.infiniteFuction();
  },
  stopInfiniteFunction() {
    cancel(this.infiniteTimer);
    this.set('infiniteTimer', undefined);
  }
});

模板:

{{#unless infiniteTimer}}
  <button onclick={{action startInfiniteFunction}}>Start</button>
{{else}}
  <button onclick={{action stopInfiniteFunction}}>Stop</button>
{{/unless}} 
于 2019-01-01T22:23:44.087 回答
0

只是为了澄清您当前的代码有什么问题(并且不一定将其作为解决方案推广),您必须更改观察者触发的值。如果您将该值设置为true,然后true稍后再将其设置为 ,而从未将其设置为false,则 Ember 将在内部忽略它并且不会重新触发观察者。请参阅此twiddle以查看使用观察者的工作示例。

代码是

init(){
    this._super(...arguments);
    this.set('count', 0);
    this.set('execute', true);
    this.timer();
  },
timer: observer('execute', function(){
    //this code is called on set to false or true
    if(this.get('execute')){
      Ember.run.later((() => {
        this.functionThatIsRunningEachTwoSeconds();
        }), 2000);
      // THIS IS SUPER IMPORTANT, COMMENT THIS OUT AND YOU ONLY GET 1 ITERATION
      this.set('execute', false);
    }
  }),
functionThatIsRunningEachTwoSeconds(){
    let count = this.get('count');
    this.set('count', count + 1);
    this.set('execute', true);
}

既然您知道您当前的方法有什么问题,让我再次记录下来,并建议这不是一种很好的、​​直观的方式来编排重复循环。我也推荐 Ember-Concurrency,因为它可以感知 Ember 生命周期

如果您处理了路线中的编辑按钮,您可以在路线更改时超级干净地取消它

functionThatIsRunningEachTwoSeconds: task(function * (id) {
    try {
      while (true) {
        yield timeout(2000);
        //work function
      }
    } finally {
      //if you wanted code after cancel
    }
}).cancelOn('deactivate').restartable()

Deactivate 对应于 ember deactivate路由钩子/事件:

当路由器完全退出此路由时,将执行此钩子。当路径的模型发生变化时,它不会被执行。

于 2019-01-03T12:12:43.433 回答