基于相同依赖项的2个计算属性仅触发一次

时间:2013-08-29 09:12:22

标签: ember.js

基于相同的依赖关系具有2个计算属性,只运行一个计算属性。文档说,如果我希望得到以下内容,那么它会被缓存:

  foo: (->
    console.log 'foo'
  ).property('dependency')

  bar: (->
    console.log 'bar'
  ).property('dependency')

现在bar没有被调用,我不得不求助于观察者。我可以让它发挥作用吗?


修改

问题是关于计算属性,但它没有反映在示例代码中 - 而不是property我使用observes。它现在改变了。抱歉混淆。


编辑#2

我修改了@MilkyWayJoe的好例子,现在它看起来像我的解决方案。不幸的是(或幸运的是)它有效,但我的解决方案并没有。以下是我追求的主旨:

借助滑块,我可以将余额值设置为转移到另一个信用卡提供商。我们假设值为transferValue。每当它发生变化时,我都必须计算转移费用的年利息。

例如,让我们说,在我目前的信用卡中,我有1000美元,年利率为19%。这太过分了,所以我寻找另一个更便宜的解决方案。事实证明,银行X提供余额转账信用卡Y,利率为10%+ 3.5%转账费。

行。所以我在滑块上设置了1000美元,这就是魔术。我想在价值变化时计算利率和转账费用。

在修改过的示例中,它有效:http://jsfiddle.net/gqSMU/2/ 但在我的第一个解决方案中未能这样做。这有点像这样:

cardInterest: (->
    apr = @get 'purchaseRate'
    amount = @get 'transferValue'
    @get('calculatedTransferFee') + @calculateInterest apr, amount
  ).property('transferValue', 'calculatedTransferFee')

如您所见,它可以访问calculatedTransferFee。问题是价值没有重新计算。我不确定值得一提,但在第一个解决方案中,Handlebars模板仅请求cardInterest

这是我目前使用观察员的解决方案:

calculatedTransferFee: 0
  transferValueDidChange: (->
    if @get('isCurrentCardChosen')
      transferFee = parseFloat @get('balanceTransferRate') / 100
      transferValue = @get 'transferValue'
      calculatedTransferFee = if isNaN(transferFee) then 0 else transferFee * transferValue
      @set 'calculatedTransferFee', calculatedTransferFee
  ).observes('transferValue')

这不是一个很好的解决方案,是吗?这就是为什么我认为这可能是一个比求助于观察者更好的解决方案。

我希望现在它更清楚了。我很感激任何进一步的反馈!

1 个答案:

答案 0 :(得分:0)

不太确定我是否理解您正在尝试实现的目标,因为您正在谈论property但您的代码正在使用observes(我意识到这是一个概念性示例代码,但不确定你要去哪里)。

通常,property将成为值的“反应访问者”,并且99.9%的时间是您希望缓存的(默认情况下,除非您说.property('whatever').volatile()),而observe会在正在观看的任何属性发生变化时触发一个函数。如果您只想为相同的依赖项触发两个属性,则可以:

App.SomeModel = Em.Object.extend({
    someDependency: true,
    foo: function() {
        // all that's in here will fire only once when 'dependency' changes, and store
        // the returning value in cache, and every time something reads this property, 
        // it will retrieve the cached value. 
        // A way to test this, is to run the following from your View: 
        // "alert(this.controller.get('content.foo'));"
        // It will alert the string but will not log "whatever bro" again. 
        console.log('whatever bro'); 
        return "this.foo %@ a dependency".fmt(this.get('someDependency') ? "has" : "doesn't have");
    }.property('someDependency'),
    bar: function() {
        // same as above
        console.log('whatever dude'); 
        return "this.bar %@ a dependency".fmt(this.get('someDependency') ? "has" : "doesn't have");

    }.property('someDependency'),
    nope: function() {
        // same as above, except this is volatile 
        // and will fire the console.log every time
        console.log('y\'all need science'); 
        return "this.nope %@ a dependency".fmt(this.get('someDependency') ? "has" : "doesn't have");

    }.property('someDependency').volatile() 
});

(见fiddle

如果您需要每次都记录它(可能是出于调试或其他原因),您可以使用volatileobserves

如果我绊倒并且这不是你想要的,也许你可以改写你的问题或者将示例代码刷新到更接近现实生活场景的地方,以澄清所问的内容。