【问题标题】:2 computed properties based on the same dependency fire only once2 个基于相同依赖项的计算属性仅触发一次
【发布时间】:2013-09-01 15:17:45
【问题描述】:

有 2 个基于相同依赖项的计算属性仅运行一个计算属性。文档说它被缓存了当我想要以下情况时怎么办:

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

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

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


编辑

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


编辑#2

我修改了@MilkyWayJoe 的出色示例,使其现在看起来像我的解决方案。不幸的是(或幸运的是)它有效,但我的解决方案没有。这是我所追求的要点:

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

例如,假设我目前的信用卡中有 1000 美元,年利率为 19%。这太多了,所以我寻找另一种更便宜的解决方案。原来X银行提供Balance Transfer Credit Card 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')

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

我希望现在它更清楚了。如有任何进一步的反馈,我将不胜感激!

【问题讨论】:

  • 你能提供一个(不)工作的例子吗?并且您确定正在请求您的两个计算属性(使用 js 或模板获取)?如果它不被调用,它将永远不会被计算。
  • @RenanTomalFernandes 这很有趣。只有第一个 foo 在模板中被请求 - 另一个 bar 不是,但我在 foo 中需要它 - 它是通过 @get 'foo' 请求的。但正如我所说,由于缓存了dependency,它没有被解雇。

标签: ember.js


【解决方案1】:

不太确定我是否理解您想要实现的目标,因为您在谈论 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

如果我绊倒了,而这不是您想要的,也许您可​​以改写您的问题或将示例代码刷新为更接近您的实际场景的内容,以澄清所问的问题。

【讨论】:

  • 感谢您的详细示例!我试图修改它,使其与真正的解决方案相似,但我没有成功。请查看更新后的问题以获取更多信息。
  • @WojtekRyrych 我之前没有看到这个评论。今天晚些时候我会检查这个
猜你喜欢
  • 2020-05-17
  • 1970-01-01
  • 2018-08-11
  • 2015-03-02
  • 2018-03-26
  • 1970-01-01
  • 2017-03-15
  • 2020-09-15
  • 1970-01-01
相关资源
最近更新 更多