计算属性在直接设置后不更新

时间:2013-07-06 16:34:19

标签: ember.js

我认为我面临一个错误,即直接将值设置为计算属性,当它的相关键再次发生变化时,它似乎会破坏计算,这里有一个例子:

o = Ember.Object.extend({
    v1: null,
    v2: function (){
        console.log('evaluation of v2', arguments);
        return this.get('v1') + '!!!';
    }.property('v1'),
    v1_Observer: function () {
        console.warn('v1 changed:', this.get('v1'));
    }.observes('v1'),
    v2_Observer: function (){
        console.info('v2 changed:', this.get('v2'));
    }.observes('v2')
});

oi = o.create();
oi.set('v1', 'Value v1 one');
oi.set('v2', 'Value direct to v2');
oi.set('v1', 'Value v1 two');
Ember.assert('v2 should be "Value v1 two!!!"', oi.get('v2') === (oi.get('v1') + '!!!'));

我认为这里有2个错误:

  1. 一切正常,直到我用“set”直接更新计算属性v2,当我再次更新v1时,v2不会被重新评估。

  2. 直接设置v2时,它的观察者被调用两次!

  3. 根据文档http://emberjs.com/guides/object-model/computed-properties/,我们可以使用'set'直接设置计算属性的值。将使用2个参数(键,值)调用!但在我的测试中,当v1第一次改变时,属性v2仅触发一次。

    这是控制台的输出:

    evaluation of v2 ["v2"]
    v2 changed: Value v1 one!!!
    v1 changed: Value v1 one
    v2 changed: Value direct
    v2 changed: Value direct
    v1 changed: Value v1 two
    Assertion failed: v2 should be "Value v1 two!!!"
    

2 个答案:

答案 0 :(得分:1)

运行示例,我在控制台中看到以下内容

> oi = o.create();

> oi.set('v1', 'Value v1 one');
[Log] evaluation of v2 ["v2"]
[Log] v2 changed: Value v1 one!!!
[Warning] v1 changed: Value v1 one

> oi.set('v2', 'Value direct to v2');
[Log] v2 changed: Value direct to v2

> oi.set('v1', 'Value v1 two');
[Log] v2 changed: Value direct to v2
[Warning] v1 changed: Value v1 two
  

直接设置v2时列出项目,其观察者被调用两次!

你可能已经注意到,'v2'的观察者在行中被调用了两次,因为你首先设置了v1的值,这使v2重新计算并且观察者开火了,它当你直接设置v2时第二次运行 - 所以没有什么好奇的。

  

列表项一切正常,直到我用“set”直接更新计算属性v2,当我再次更新v1时,v2不会被重新评估。

一旦手动设置v2,你基本上就会告诉计算属性消失并用一个值替换它(实质上,v2是一个函数,你将它设置为一个值)。为什么会重新评估?

答案 1 :(得分:1)

Ember使用runloop来优化绑定并将DOM更新保持为最小值。它通过将这些属性更改放在队列中来实现。然而,队列更聪明一些。

如果您要在将属性呈现给DOM之前修改属性10次,它将仅使用您为该属性设置的最后一个值。因此,当您需要在DOM中显示属性时,只需要更新一次。

此外,计算属性是一个函数,它根据传入的参数数量充当getter和setter。语法是,

myProperty: function(key, value) {
  if (value) {
    // setter
  } else {
    // getter
  }
}.property()

在上面的示例中,您只返回从依赖v1计算的值。您还需要提供一个setter,将值从v1计算属性中反馈回v2