在Ember应用程序中SetTimeout与Ember.run.later?

时间:2014-02-02 00:01:55

标签: ember.js handlebars.js momentjs

在我的车把模板中:

Today's date: {{currentDate}}
Current Time: {{currentTime}}

在我的助手里面:

Ember.Handlebars.registerBoundHelper 'currentDate', (option) ->
  moment().format('LL');

Ember.Handlebars.registerBoundHelper 'currentTime', (option) ->
  moment().format('h:mm:ss a');

我如何每1秒更新一次currentTime到视图?

我已阅读Ember推荐的Ember.run.later,但我无法弄清楚将它放在何处以及如何使用此助手调用它。

5 个答案:

答案 0 :(得分:52)

您可以像使用setTimeout

一样使用Ember.run.later
Ember.run.later((function() {
  //do something in here that will run in 2 seconds
}), 2000);

我不确定内部是什么,但我知道集成测试Ember要求你使用run.later(如果你不测试代码不会等待超时完成)。

答案 1 :(得分:11)

您不希望将超时添加到帮助程序中,您需要将其添加到全局变量中,然后从中执行差异操作。你想要使用Em.run.later的原因是它会将它注入到运行循环中(Toran所获得的部分)。这对测试非常重要。

将时间添加到全局变量

App.ApplicationRoute = Em.Route.extend({
  setupController: function(controller, model){
    this._super(controller, model);
    this.startWatchingTime(controller);
  },
  startWatchingTime: function(controller){
    var self = this;
    controller.set('currentTime', moment());
    Em.run.later(function(){
      self.startWatchingTime(controller);
    }, 1000);
  }
});

将其添加到帮助程序

Ember.Handlebars.helper('time-diff', function(date1, date2, format, options) {
  return date1.diff(date2, format);
});

将其发送给帮助者

{{time-diff  controllers.application.currentTime anotherTime 'seconds'}}

http://emberjs.jsbin.com/UcUrIQa/1/edit

答案 2 :(得分:6)

你想使用Embers.run循环,而不是使用setTimer。

当前(今天)版本的ember需要使用context this格式(更新Toran Billups答案)

this._debouncedItem = Ember.run.later(this, () => {
   debugger;
}, 5000);

我强烈建议保留对later()的响应的引用,并在destroy hook中取消它

destroy() {
   this._super(...arguments);
   Ember.run.cancel(this._debouncedItem);
},

答案 3 :(得分:2)

你可以使currentDate成为常规财产

currentDate: null,
currentTime: null

您可以在控制器的构造函数中启动此计时器。

init: function () { 
  this.updateTimeProperty();
},
updateTimeProperty: function () {
  var _this = this;
  Ember.run.later(this, function() {
    _this.currentDate = moment().format('LL');
    _this.set('currentTime',  moment().format('h:mm:ss a');
    _this.updateTimeProperty());
  }, 1000);
}

答案 4 :(得分:1)

我有点过时的Ember用户,但我会这样做,希望有更好的解决方案。

App.CurrentTimeView = Ember.View.extend({
    template : Ember.Handlebars.compile("<span>{{view.currentTime}}</span>"),
    currentTime : null,
    init : function(){
        var view = this;
        view.set('currentTime', moment().format('h:mm:ss a'));
        setInterval((function(view){
            return function(){view.set('currentTime', moment().format('h:mm:ss a'));};
        })(view),1000);
    }
});

并在模板中

{{view "App.CurrentTimeView"}}

要回答你的问题, Javascript具有单线程执行(除非您使用webworkers),这意味着它将以串行方式逐个执行。当您使用setInterval时,它将每隔x毫秒将您的函数排入此主执行队列。 setInterval使用传递的time进行排队。 Ember运行循环将计算每个运行循环中的绑定和其他重要事物,因此在循环结束时我们确定已经准备好了更改。有像Em.run.next这样的钩子,以确保这些代码在运行时将在上一次运行循环中完成更改。类似地,当你将时间传递给Em.run.later时,它也将在那么多时间后运行,并且还支持在函数内设置this的参数。主要是在处理函数内部的某些变量或模型/控制器数据时。

在你的情况下,setInterval看起来没问题(对我而言)。

http://jsfiddle.net/NQKvy/604/