观察者(observer)

简介: 观察者(observer)
Ember可以检测任何属性的变化,包括计算属性。
image.png

观察者使用

Ember可以察觉所有属性的变化,包括计算属性。观察者是非常有用的,特别是计算属性绑定之后需要同步的时候。
观察者经常被Ember开发过度使用。Ember框架本身已经大量使用观察者,但是对于大多数的开发者面对开发问题时使用计算属性是更适合的解决方案。
使用方式:可以用Ember.observer创建一个对象为观察者。

// Observer对于Emberjs来说非常重要,前面你看到的很多代码都是与它有关系,计算属性之所以能更新也是因为它
Person = Ember.Object.extend({
  firstName: null,
  lastName: null,

  fullName: Ember.computed('firstName', 'lastName', function() {
    return this.get('firstName') + " " + this.get('lastName');
  }),

  //  当fullName被改变的时候触发观察者
  fullNameChange: Ember.observer('fullName', function() {
    console.log("The fullName is changed by caller");
    //return this.get('fullName');
  })
});

var person = Person.create({
  firstName: 'chen',
  lastName: 'ubuntuvim'
});
// 如果被观察的计算属性还没执行过get()方法不会触发观察者
console.log('fullName = ' + person.get('fullName'));  
//  fullName是依赖firstName和lastName的,这里改变了firstName的值,计算属性会自动更新,
//  fullName被改变了所以会触发观察者
person.set('firstName', 'change firstName value');  // 观察者会被触发
console.log('fullName = ' + person.get('fullName'));

fullName是依赖firstNamelastName的,调用set()方法改变了firstName的值,自然的导致fullName的值也被改变了,fullName变化了就触发观察者。从执行的结果就可以看出来;

Ember还为开发者提供了另一种使用观察者的方式。这种方式使你可以在类定义之外为某个计算属性增加一个观察者。

person.addObserver('fullName', function() {
    // deal with the change…
});

观察者与异步

目前,观察者在Ember中是同步的(不是笔误,官网就是这么说的Observers in Ember are currently synchronous.)。这就意味着只要计算属性一发生变化就会触发观察者。也因为这个原因很容易就会引入这样的bug在计算属性没有同步的时候。比如下面的代码;

Person.reopen({
  lastNameChanged: Ember.observer('lastName', 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'));
  })
});

然而由于同步的原因如果你的的观察者同时观察多个属性,就会导致观察者执行多次。

person = Ember.Object.extend({
  firstName: null,
  lastName: null,

  fullName: Ember.computed('firstName', 'lastName', function() {
    return this.get('firstName') + " " + this.get('lastName');
  }),

  //  当fullName被改变的时候触发观察者
  fullNameChange: Ember.observer('fullName', function() {
    console.log("The fullName is changed by caller");
    //return this.get('fullName');
  })
});
Person.reopen({
  partOfNameChanged: Ember.observer('firstName', 'lastName', function() {
    //  同时观察了firstName和lastName两个属性
    console.log('========partOfNameChanged======');
  })
});
var person = Person.create({
  firstName: 'chen',
  lastName: 'ubuntuvim'
});

person.set('firstName', '[firstName]');
person.set('lastName', '[lastName]');

显然上述代码执行了两次set()所以观察者也会执行2次,但是如果开发中需要设置只能执行一次观察出呢?Ember提供了一个once()方法,这个方法会在下一次循环所有绑定属性都同步的时候执行。

Person = Ember.Object.extend({
  firstName: null,
  lastName: null,

  fullName: Ember.computed('firstName', 'lastName', function() {
    return this.get('firstName') + " " + this.get('lastName');
  }),

  //  当fullName被改变的时候触发观察者
  fullNameChange: Ember.observer('fullName', function() {
    console.log("The fullName is changed by caller");
    //return this.get('fullName');
  })
});
Person.reopen({
  partOfNameChanged: Ember.observer('firstName', 'lastName', function() {
    //  同时观察了firstName和lastName两个属性
    //  方法partOfNameChanged本身还是会执行多次,但是方法processFullName只会执行一次
    console.log('========partOfNameChanged======');  //  
    Ember.run.once(this, 'processFullName');
  }),
  processFullName: Ember.observer('fullName', function() {
    // 当你同时设置多个属性的时候,此观察者只会执行一次,并且是发生在下一次所有属性都被同步的时候
    console.log('fullName = ' + this.get('fullName'));
  })
});

var person = Person.create({
  firstName: 'chen',
  lastName: 'ubuntuvim'
});

person.set('firstName', '[firstName]');
person.set('lastName', '[lastName]');

观察者与对象初始化

观察者一直到对象初始化完成之后才会执行。
如果你想观察者在对象初始化的时候就执行你必须要手动调用Ember.on()方法。这个方法会在对象初始化之后就执行。

Person = Ember.Object.extend({
  salutation:null,
  init() {
    this.set('salutation', 'hello');
    console.log('init....');
  },
  salutationDidChange: Ember.on('init', Ember.observer('salutation', function() {
    console.log('salutationDidChange......');
  }))
});

var p = Person.create();
p.get('salutationDidChange');  //  output > init....  salutationDidChange......
console.log(p.get('salutation'));  // output > hello
p.set('salutation');  //  output > salutationDidChange......

未获取过值的计算属性不会触发观察者

如果一个计算属性从来没有调用过get()方法获取的其值,观察者就不会被触发,即使是计算属性的值发生变化了。你可以这么认为,观察者是根据调用get()方法前后的值比较判断出计算属性值是否发生改变了。如果没调用过get()之前的改变观察者认为是没有变化。

通常我们不需要担心这个问题会影响到程序代码,因为几乎所有被观察的计算属性在触发前都会执行取值操作。如果你仍然担心观察者不会被触发,你可以在`init()`方法了执行一次`get`操作。这样足以保证你的观察在触发之前是执行过get操作的。


相关文章
RxSwift观察者AnyObserver、Binder的使用
RxSwift观察者AnyObserver、Binder的使用
138 0
|
存储 JavaScript 前端开发
RxJS系列02:可观察者 Observables
RxJS系列02:可观察者 Observables
112 0
|
设计模式 Java
Java设计模式-观察者模式(Observer)
Java设计模式-观察者模式(Observer)
|
Java 程序员
行为型模式 - 观察者模式(Observer Pattern)
行为型模式 - 观察者模式(Observer Pattern)
rxJava中 Subscriber 与Observer
rxJava中 Subscriber 与Observer
218 0
|
设计模式 大数据
行为型-Observer
行为型设计模式主要解决的就是“类或对象之间的交互”问题。 原理及应用场景剖析 观察者模式(Observer Design Pattern)也被称为发布订阅模式(Publish-Subscribe Design Pattern)。在 GoF 的《设计模式》一书中,它的定义是这样的: Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically. 翻译成中文就是:在对象之间
121 0
|
存储 设计模式 Java
浅谈JAVA设计模式之——观察者模式(Observer)
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
187 0
浅谈JAVA设计模式之——观察者模式(Observer)
|
前端开发 JavaScript NoSQL
5. 创建 Observable
第一个示例 注册事件监听器的常规写法。 var button = document.querySelector('button'); button.addEventListener('click', () => console.
986 0
观察者模式(Observer )
对象间的联动——观察者模式(一)对象间的联动——观察者模式(二)对象间的联动——观察者模式(三)对象间的联动——观察者模式(四)对象间的联动——观察者模式(五)对象间的联动——观察者模式(五)
769 0