Ember学习(6):Observers

来源:互联网 发布:最流行编程语言 编辑:程序博客网 时间:2024/05/18 00:04

英文原址:http://emberjs.com/guides/object-model/observers/


Ember支持监听任何属性,包括计算型属性。你可以通过对函数使用observes来针对一个对象创建observer。

Person = Ember.Object.extend({  // these will be supplied by `create`  firstName: null,  lastName: null,  fullName: function() {    var firstName = this.get('firstName');    var lastName = this.get('lastName');    return firstName + ' ' + lastName;  }.property('firstName', 'lastName'),  fullNameChanged: function() {    // deal with the change  }.observes('fullName').on('init')});var person = Person.create({  firstName: 'Yehuda',  lastName: 'Katz'});person.set('firstName', 'Brohuda'); // observer will fire
因为fullName计算型属性依赖firstName属性,更新firstName也会触发fullName的observer。

观察者和异步

目前Ember中Observer都是同步的,这意味着observer方法会在他们观察的属性被改变的当时就被触发,因为这个原因,当属性不是同步方式使用时,容易引入一些bug。

Person.reopen({  lastNameChanged: function() {    // The observer depends on lastName and so does fullName. Because observers    // are synchronous, when this function is called the value of fullName is    // not updated yet so this will log the old value of fullName    console.log(this.get('fullName'));  }.observes('lastName')});
上面的observer依赖lastName,也需要调用fullName。因为observer是同步的,当这个函数被调用时,fullName的值还没有来得及更新,因此它会打印出fullName的旧值。

这种同步的机制也会导致同一个observer被触发多次,当这个observer同时监听多个属性时。

Person.reopen({  partOfNameChanged: function() {    // Because both firstName and lastName were set, this observer will fire twice.  }.observes('firstName', 'lastName')});person.set('firstName', 'John');person.set('lastName', 'Smith');

为了避免这样的问题,你应该使用Ember.run.once。这会保证任何你需要做的事情只会被执行一次,当所有绑定都是同步方式时,只在下一次run loop中发生一次。(这里还是有点不太理解,没有使用过,回头理解的更透彻了,再细说)

Person.reopen({  partOfNameChanged: function() {    Ember.run.once(this, 'processFullName');  }.observes('firstName', 'lastName'),  processFullName: function() {    // This will only fire once if you set two properties at the same time, and    // will also happen in the next run loop once all properties are synchronized    console.log(this.get('fullName'));  }});person.set('firstName', 'John');person.set('lastName', 'Smith');

观察者和对象初始化

只有一个对象的初始化完成了后,observer才会被触发。如果你需要observer在初始化发生时也被触发,你不能依赖set方法的副作用,你需要使用.on('init')来说明这个observer在初始化时也需要被触发。

App.Person = Ember.Object.extend({  init: function() {    this.set('salutation', "Mr/Ms");  },  salutationDidChange: function() {    // some side effect of salutation changing  }.observes('salutation').on('init')});

没有被调用的计算型属性不会触发观察者

如果你从来没有对一个计算型属性使用get方法,它的observer永远也不会被触发,即使是该计算型属性依赖的属性发生了变化。你可以想象成它的值从一个unknown值变成另外一个。
这通常都不会影响应用的代码,因为计算型属性通常基本上被观察的同时也会被访问。举个例子,你访问了一个计算型属性的值,将它插入了HTML DOM(或者使用D3画出来),然后你监听它,当它改变时,你可以更新DOM。
如果你需要监听一个计算型属性,但是却不马上读取该计算型属性,你可以在init方法中读取它。

不使用Prototype扩展

如果你没有使用Ember的Prototype扩展,那么你可以使用Ember.observer方法来定义observer:
Person.reopen({  fullNameChanged: Ember.observer('fullName', function() {    // deal with the change  })});

在类定义外面使用

你也可以在一个类定义的外面通过使用addObserver方法来给某个对象添加observer:
person.addObserver('fullName', function() {  // deal with the change});

0 0