EmberJS 對象模型觀察器和異步

2020-07-17 09:38 更新

Ember 為包括計(jì)算后屬性在內(nèi)的任意一種屬性提供了觀察器??梢酝ㄟ^使用 addObserver 方法來為一個(gè)對象設(shè)置一個(gè)觀察器:

Person = Ember.Object.extend({
  // 這些屬性將由 `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() {
    // 處理改變
  }.observes('fullName').on('init')
});

var person = Person.create({
  firstName: "Yehuda",
  lastName: "Katz"
});

person.set('firstName', "Brohuda"); // 觀察器將被觸發(fā)

由于 fullName 這個(gè)計(jì)算后屬性依賴于 firstName 的變化,所以在更新 firstName 時(shí)也將觸發(fā) fullName 上的觀察器。

觀察器與異步

Ember中的觀察器目前都是同步的。這就意味著一旦其觀察的屬性發(fā)生改變就立刻會被觸發(fā)。因?yàn)檫@樣,找到屬性沒有被及時(shí)同步就變得容易了:

Person.reopen({
  lastNameChanged: function() {
    // 該觀察器和 fullName 都依賴于 lastName。因?yàn)橛^察器都是異步的,當(dāng)該函數(shù)被調(diào)用時(shí), 
    // fullName 還沒有被更新,因此這里會打印出 fullName 的舊值。
    console.log(this.get('fullName'));
  }.observes('lastName')
});

如果觀察了多個(gè)屬性,那么同步行為也會導(dǎo)致觀察器被多次觸發(fā):

Person.reopen({
  partOfNameChanged: function() {
    // 因?yàn)?firstName 和 lastName 都被設(shè)置了,將觸發(fā)兩次更新
  }.observes('firstName', 'lastName')
});

person.set('firstName', 'John');
person.set('lastName', 'Smith');

為了處理這些問題,就需要使用 Ember.run.once 。這樣可以確保所有需要處理的過程都只會發(fā)生一次,并且在下一個(gè)運(yùn)行循環(huán)里面所有綁定都會同步:

Person.reopen({
  partOfNameChanged: function() {
    Ember.run.once(this, 'processFullName');
  }.observes('firstName', 'lastName'),

  processFullName: function() {
    // 如果兩個(gè)屬性都被設(shè)置,同步更新會一步到位
    console.log(this.get('fullName'));
  }
});

person.set('firstName', 'John');
person.set('lastName', 'Smith');

觀察器與對象初始化

觀察器只有對象完成了初始化過程之后才會被觸發(fā)。

如果需要在初始化過程中就觸發(fā)一個(gè)觀察器,那么不能依賴于 set 的負(fù)效應(yīng)。而應(yīng)該在觀察器上,通過使用.on('init')指定觀察器應(yīng)該在初始化后執(zhí)行:

App.Person = Ember.Object.extend({
  init: function() {
    this.set('salutation', "Mr/Ms");
  },

  salutationDidChange: function() {
    // 一些 salutation 的負(fù)效應(yīng)正在改變
  }.observes('salutation').on('init')
});

未使用的計(jì)算屬性不觸發(fā)觀察器

如果從未 get 一個(gè)計(jì)算屬性,那么即使它依賴的鍵發(fā)生改變了,觀察器也不會被觸發(fā)??梢哉J(rèn)為這時(shí)是計(jì)算屬性值從一個(gè)未知值轉(zhuǎn)換為另一個(gè)。

這通常都不會影響到應(yīng)用代碼,因?yàn)橛?jì)算屬性幾乎總是在被觀察到的同時(shí)被取用。例如,取得一個(gè)計(jì)算屬性的值,然后將其放入DOM中(或者用D3畫出),然后觀察它,以便在屬性發(fā)生改變的時(shí)候自動更新DOM。

如果需要觀察一個(gè)計(jì)算屬性,當(dāng)前并不獲取它,只需要將其放入到 init 方法中。

不用原型擴(kuò)展

在沒有原型擴(kuò)展的前提下使用 Ember 的時(shí)候,可以用 Ember.observer 方法來定義內(nèi)聯(lián)式觀察器:

Person.reopen({
  fullNameChanged: Ember.observer('fullName', function() {
    // 這是內(nèi)聯(lián)式版本的 .addObserver
  })
});

類定義之外

同樣也可以在一個(gè)類的定義之外,使用 addObserver 為一個(gè)對象添加一個(gè)觀察器:

person.addObserver('fullName', function() {
  // 更新的處理
});


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號